rubylabs 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
data/bin/statistics2.rb DELETED
@@ -1,532 +0,0 @@
1
- #! /usr/bin/env ruby
2
-
3
- # statistics2.rb
4
- #
5
- # distributions of statistics
6
- # by Shin-ichiro HARA
7
- #
8
- # 2003.09.25
9
- #
10
- # Ref:
11
- # [1] http://www.matsusaka-u.ac.jp/~okumura/algo/
12
- # [2] http://www5.airnet.ne.jp/tomy/cpro/sslib11.htm
13
-
14
- module Statistics2
15
- SQ2PI = Math.sqrt(2 * Math::PI)
16
-
17
- # Newton approximation
18
- def newton_a(y, ini, epsilon = 1.0e-6, limit = 30)
19
- x = ini
20
- limit.times do |i|
21
- prev = x
22
- f, df = yield(prev)
23
- x = (y - f)/df + prev
24
- if (x - prev).abs < epsilon
25
- return x
26
- end
27
- end
28
- $stderr.puts("Warning(newton approximation): over limit")
29
- x
30
- end
31
-
32
- module_function :newton_a
33
- private :newton_a
34
- private_class_method :newton_a
35
-
36
- # Gamma function
37
- LOG_2PI = Math.log(2 * Math::PI)# log(2PI)
38
- N = 8
39
- B0 = 1.0
40
- B1 = -1.0 / 2.0
41
- B2 = 1.0 / 6.0
42
- B4 = -1.0 / 30.0
43
- B6 = 1.0 / 42.0
44
- B8 = -1.0 / 30.0
45
- B10 = 5.0 / 66.0
46
- B12 = -691.0 / 2730.0
47
- B14 = 7.0 / 6.0
48
- B16 = -3617.0 / 510.0
49
-
50
- def loggamma(x)
51
- v = 1.0
52
- while (x < N)
53
- v *= x
54
- x += 1.0
55
- end
56
- w = 1.0 / (x * x)
57
- ret = B16 / (16 * 15)
58
- ret = ret * w + B14 / (14 * 13)
59
- ret = ret * w + B12 / (12 * 11)
60
- ret = ret * w + B10 / (10 * 9)
61
- ret = ret * w + B8 / ( 8 * 7)
62
- ret = ret * w + B6 / ( 6 * 5)
63
- ret = ret * w + B4 / ( 4 * 3)
64
- ret = ret * w + B2 / ( 2 * 1)
65
- ret = ret / x + 0.5 * LOG_2PI - Math.log(v) - x + (x - 0.5) * Math.log(x)
66
- ret
67
- end
68
-
69
- def gamma(x)
70
- if (x < 0.0)
71
- return Math::PI / (Math.sin(Math.PI * x) * Math.exp(loggamma(1 - x))) #/
72
- end
73
- Math.exp(loggamma(x))
74
- end
75
-
76
- module_function :loggamma, :gamma
77
- private :loggamma, :gamma
78
- private_class_method :loggamma, :gamma
79
-
80
- #normal-distribution
81
- # (-\infty, z]
82
- def p_nor(z)
83
- if z < -12 then return 0.0 end
84
- if z > 12 then return 1.0 end
85
- if z == 0.0 then return 0.5 end
86
-
87
- if z > 0.0
88
- e = true
89
- else
90
- e = false
91
- z = -z
92
- end
93
- z = z.to_f
94
- z2 = z * z
95
- t = q = z * Math.exp(-0.5 * z2) / SQ2PI
96
-
97
- 3.step(199, 2) do |i|
98
- prev = q
99
- t *= z2 / i
100
- q += t
101
- if q <= prev
102
- return(e ? 0.5 + q : 0.5 - q)
103
- end
104
- end
105
- e ? 1.0 : 0.0
106
- end
107
-
108
- # inverse of normal distribution ([2])
109
- # Pr( (-\infty, x] ) = qn -> x
110
- def pnorm(qn)
111
- b = [1.570796288, 0.03706987906, -0.8364353589e-3,
112
- -0.2250947176e-3, 0.6841218299e-5, 0.5824238515e-5,
113
- -0.104527497e-5, 0.8360937017e-7, -0.3231081277e-8,
114
- 0.3657763036e-10, 0.6936233982e-12]
115
-
116
- if(qn < 0.0 || 1.0 < qn)
117
- $stderr.printf("Error : qn <= 0 or qn >= 1 in pnorm()!\n")
118
- return 0.0;
119
- end
120
- qn == 0.5 and return 0.0
121
-
122
- w1 = qn
123
- qn > 0.5 and w1 = 1.0 - w1
124
- w3 = -Math.log(4.0 * w1 * (1.0 - w1))
125
- w1 = b[0]
126
- 1.upto 10 do |i|
127
- w1 += b[i] * w3**i;
128
- end
129
- qn > 0.5 and return Math.sqrt(w1 * w3)
130
- -Math.sqrt(w1 * w3)
131
- end
132
-
133
- private :p_nor, :pnorm
134
- module_function :p_nor, :pnorm
135
- private_class_method :p_nor, :pnorm
136
-
137
- #normal-distribution interface
138
- def normaldist(z)
139
- p_nor(z)
140
- end
141
-
142
- def pnormaldist(y)
143
- pnorm(y)
144
- end
145
-
146
- #chi-square distribution ([1])
147
- #[x, \infty)
148
- def q_chi2(df, chi2)
149
- chi2 = chi2.to_f
150
- if (df & 1) != 0
151
- chi = Math.sqrt(chi2)
152
- if (df == 1) then return 2 * normal___x(chi); end
153
- s = t = chi * Math.exp(-0.5 * chi2) / SQ2PI
154
- k = 3
155
- while k < df
156
- t *= chi2 / k; s += t;
157
- k += 2
158
- end
159
- 2 * (normal___x(chi) + s)
160
- else
161
- s = t = Math.exp(-0.5 * chi2)
162
- k = 2
163
- while k < df
164
- t *= chi2 / k; s += t;
165
- k += 2
166
- end
167
- s
168
- end
169
- end
170
-
171
- def chi2dens(n, x)
172
- if n == 1
173
- 1.0/Math.sqrt(2 * Math::PI * x) * Math::E**(-x/2.0)
174
- elsif n == 2
175
- 0.5 * Math::E**(-x/2.0)
176
- else
177
- n = n.to_f
178
- n2 = n/2
179
- x = x.to_f
180
- 1.0 / 2**n2 / gamma(n2) * x**(n2 - 1.0) * Math.exp(-x/2.0)
181
- end
182
- end
183
-
184
- # [x, \infty)
185
- # Pr([x, \infty)) = y -> x
186
- def pchi2(n, y)
187
- if n == 1
188
- w = pnorm(1 - y/2) # = pnormal___x(y/2)
189
- w * w
190
- elsif n == 2
191
- # v = (1.0 / y - 1.0) / 33.0
192
- # newton_a(y, v) {|x| [q_chi2(n, x), -chi2dens(n, x)] }
193
- -2.0 * Math.log(y)
194
- else
195
- eps = 1.0e-5
196
- v = 0.0
197
- s = 10.0
198
- loop do
199
- v += s
200
- if s <= eps then break end
201
- if (qe = q_chi2(n, v) - y) == 0.0 then break end
202
- if qe < 0.0
203
- v -= s
204
- s /= 10.0 #/
205
- end
206
- end
207
- v
208
- end
209
- end
210
-
211
- private :q_chi2, :pchi2, :chi2dens
212
- module_function :q_chi2, :pchi2, :chi2dens
213
- private_class_method :q_chi2, :pchi2, :chi2dens
214
-
215
- # chi-square-distribution interface
216
- def chi2dist(n, x); 1.0 - q_chi2(n, x); end
217
- def pchi2dist(n, y); pchi2(n, 1.0 - y); end
218
-
219
-
220
- # t-distribution ([1])
221
- # (-\infty, x]
222
- def p_t(df, t)
223
- c2 = df.to_f / (df + t * t);
224
- s = Math.sqrt(1.0 - c2)
225
- s = -s if t < 0.0
226
- p = 0.0;
227
- i = df % 2 + 2
228
- while i <= df
229
- p += s
230
- s *= (i - 1) * c2 / i
231
- i += 2
232
- end
233
- if df & 1 != 0
234
- 0.5+(p*Math.sqrt(c2)+Math.atan(t/Math.sqrt(df)))/Math::PI
235
- else
236
- (1.0 + p) / 2.0
237
- end
238
- end
239
-
240
- # inverse of t-distribution ([2])
241
- # (-\infty, -q/2] + [q/2, \infty)
242
- def ptsub(q, n)
243
- q = q.to_f
244
- if(n == 1 && 0.001 < q && q < 0.01)
245
- eps = 1.0e-4
246
- elsif (n == 2 && q < 0.0001)
247
- eps = 1.0e-4
248
- elsif (n == 1 && q < 0.001)
249
- eps = 1.0e-2
250
- else
251
- eps = 1.0e-5
252
- end
253
- s = 10000.0
254
- w = 0.0
255
- loop do
256
- w += s
257
- if(s <= eps) then return w end
258
- if((qe = 2.0 - p_t(n, w)*2.0 - q) == 0.0) then return w end
259
- if(qe < 0.0)
260
- w -= s
261
- s /= 10.0 #/
262
- end
263
- end
264
- end
265
-
266
- def pt(q, n)
267
- q = q.to_f
268
- if(q < 1.0e-5 || q > 1.0 || n < 1)
269
- $stderr.printf("Error : Illigal parameter in pt()!\n")
270
- return 0.0
271
- end
272
-
273
- if(n <= 5) then return ptsub(q, n) end
274
- if(q <= 5.0e-3 && n <= 13) then return ptsub(q, n) end
275
-
276
- f1 = 4.0 * (f = n.to_f)
277
- f5 = (f4 = (f3 = (f2 = f * f) * f) * f) * f
278
- f2 *= 96.0
279
- f3 *= 384.0
280
- f4 *= 92160.0
281
- f5 *= 368640.0
282
- u = pnormaldist(1.0 - q / 2.0)
283
-
284
- w0 = (u2 = u * u) * u
285
- w1 = w0 * u2
286
- w2 = w1 * u2
287
- w3 = w2 * u2
288
- w4 = w3 * u2
289
- w = (w0 + u) / f1
290
- w += (5.0 * w1 + 16.0 * w0 + 3.0 * u) / f2
291
- w += (3.0 * w2 + 19.0 * w1 + 17.0 * w0 - 15.0 * u) / f3
292
- w += (79.0 * w3 + 776.0 * w2 + 1482.0 * w1 - 1920.0 * w0 - 9450.0 * u) / f4
293
- w += (27.0 * w4 + 339.0 * w3 + 930.0 * w2 - 1782.0 * w1 - 765.0 * w0 + 17955.0 * u) / f5
294
- u + w
295
- end
296
-
297
- private :p_t, :pt, :ptsub
298
- module_function :p_t, :pt, :ptsub
299
- private_class_method :p_t, :pt, :ptsub
300
-
301
- # t-distribution interface
302
- def tdist(n, t); p_t(n, t); end
303
- def ptdist(n, y)
304
- if y > 0.5
305
- pt(2.0 - y*2.0, n)
306
- else
307
- - pt(y*2.0, n)
308
- end
309
- end
310
-
311
- # F-distribution ([1])
312
- # [x, \infty)
313
- def q_f(df1, df2, f)
314
- if (f <= 0.0) then return 1.0; end
315
- if (df1 % 2 != 0 && df2 % 2 == 0)
316
- return 1.0 - q_f(df2, df1, 1.0 / f)
317
- end
318
- cos2 = 1.0 / (1.0 + df1.to_f * f / df2.to_f)
319
- sin2 = 1.0 - cos2
320
-
321
- if (df1 % 2 == 0)
322
- prob = cos2 ** (df2.to_f / 2.0)
323
- temp = prob
324
- i = 2
325
- while i < df1
326
- temp *= (df2.to_f + i - 2) * sin2 / i
327
- prob += temp
328
- i += 2
329
- end
330
- return prob
331
- end
332
- prob = Math.atan(Math.sqrt(df2.to_f / (df1.to_f * f)))
333
- temp = Math.sqrt(sin2 * cos2)
334
- i = 3
335
- while i <= df1
336
- prob += temp
337
- temp *= (i - 1).to_f * sin2 / i.to_f;
338
- i += 2.0
339
- end
340
- temp *= df1.to_f
341
- i = 3
342
- while i <= df2
343
- prob -= temp
344
- temp *= (df1.to_f + i - 2) * cos2 / i.to_f
345
- i += 2
346
- end
347
- prob * 2.0 / Math::PI
348
- end
349
-
350
- # inverse of F-distribution ([2])
351
- def pfsub(x, y, z)
352
- (Math.sqrt(z) - y) / x / 2.0
353
- end
354
-
355
- # [x, \infty)
356
- def pf(q, n1, n2)
357
- if(q < 0.0 || q > 1.0 || n1 < 1 || n2 < 1)
358
- $stderr.printf("Error : Illegal parameter in pf()!\n")
359
- return 0.0
360
- end
361
-
362
- if n1 <= 240 || n2 <= 240
363
- eps = 1.0e-5
364
- if(n2 == 1) then eps = 1.0e-4 end
365
- fw = 0.0
366
- s = 1000.0
367
- loop do
368
- fw += s
369
- if s <= eps then return fw end
370
- if (qe = q_f(n1, n2, fw) - q) == 0.0 then return fw end
371
- if qe < 0.0
372
- fw -= s
373
- s /= 10.0 #/
374
- end
375
- end
376
- end
377
-
378
- eps = 1.0e-6
379
- qn = q
380
- if q < 0.5 then qn = 1.0 - q
381
- u = pnorm(qn)
382
- w1 = 2.0 / n1 / 9.0
383
- w2 = 2.0 / n2 / 9.0
384
- w3 = 1.0 - w1
385
- w4 = 1.0 - w2
386
- u2 = u * u
387
- a = w4 * w4 - u2 * w2
388
- b = -2. * w3 * w4
389
- c = w3 * w3 - u2 * w1
390
- d = b * b - 4 * a * c
391
- if(d < 0.0)
392
- fw = pfsub(a, b, 0.0)
393
- else
394
- if(a.abs > eps)
395
- fw = pfsub(a, b, d)
396
- else
397
- if(b.abs > eps) then return -c / b end
398
- fw = pfsub(a, b, 0.0)
399
- end
400
- end
401
- fw * fw * fw
402
- end
403
- end
404
-
405
- private :q_f, :pf, :pfsub
406
- module_function :q_f, :pf, :pfsub
407
- private_class_method :q_f, :pf, :pfsub
408
-
409
- # F-distribution interface
410
- def fdist(n1, n2, f); 1.0 - q_f(n1, n2, f); end
411
- def pfdist(n1, n2, y); pf(1.0 - y, n1, n2); end
412
-
413
- ############################################################################
414
- # discrete distributions
415
-
416
- def perm(n, x = n)
417
- raise RangeError if n < 0 || x < 0
418
- r = 1
419
- while x >= 1
420
- r *= n
421
- n -= 1
422
- x -= 1
423
- end
424
- r
425
- end
426
-
427
- def combi(n, x)
428
- raise RangeError if n < 0 || x < 0
429
- x = n - x if x*2 > n
430
- perm(n, x) / perm(x, x)
431
- end
432
-
433
- module_function :perm, :combi
434
- private_class_method :perm, :combi
435
-
436
- def bindens(n, p, x)
437
- p = p.to_f
438
- q = 1.0 - p
439
- combi(n, x) * p**x * q**(n - x)
440
- end
441
-
442
- def bindist(n, p, x)
443
- (0..x).inject(0.0) do |s, k|
444
- s + bindens(n, p, k)
445
- end
446
- end
447
-
448
- def poissondens(m, x)
449
- return 0.0 if x < 0
450
- m = m.to_f
451
- m ** x * Math::E ** (-m) / perm(x)
452
- end
453
-
454
- def poissondist(m, x)
455
- (0..x).inject(0.0) do |s, k|
456
- s + poissondens(m, k)
457
- end
458
- end
459
-
460
- ############################################################################
461
-
462
- # normal-distribution
463
- def normalxXX_(z); normaldist(z); end
464
- def normal__X_(z); normaldist(z) - 0.5; end
465
- def normal___x(z); 1.0 - normaldist(z); end
466
- def normalx__x(z); 2.0 - normaldist(z) * 2.0; end
467
- module_function :normaldist, :normalxXX_, :normal__X_, :normal___x, :normalx__x
468
-
469
- # inverse of normal-distribution
470
- def pnormalxXX_(z); pnormaldist(z); end
471
- def pnormal__X_(y); pnormalxXX_(y + 0.5); end
472
- def pnormal___x(y); pnormalxXX_(1.0 - y); end
473
- def pnormalx__x(y); pnormalxXX_(1.0 - y/2.0); end
474
- module_function :pnormaldist, :pnormalxXX_, :pnormal__X_, :pnormal___x, :pnormalx__x
475
-
476
-
477
- # chi2-distribution
478
- def chi2_x(n, x); 1.0 - chi2dist(n, x); end
479
- def chi2X_(n, x); chi2dist(n, x); end
480
- module_function :chi2dist, :chi2X_, :chi2_x
481
-
482
- # inverse of chi2-distribution
483
- def pchi2_x(n, y); pchi2dist(n, 1.0 - y); end
484
- def pchi2X_(n, y); pchi2dist(n, y); end
485
- module_function :pchi2dist, :pchi2X_, :pchi2_x
486
-
487
-
488
- # t-distribution
489
- def tx__x(n, x); 2.0 - tdist(n, x) * 2.0; end
490
- def txXX_(n, x); tdist(n, x); end
491
- def t__X_(n, x); tdist(n, x) - 0.5; end
492
- def t___x(n, x); 1.0 - tdist(n, x); end
493
- module_function :tdist, :txXX_, :t__X_, :t___x, :tx__x
494
-
495
- # inverse of t-distribution
496
- def ptx__x(n, y); ptdist(n, 1.0 - y / 2.0); end
497
- def ptxXX_(n, y); ptdist(n, y); end
498
- def pt__X_(n, y); ptdist(n, 0.5 + y); end
499
- def pt___x(n, y); ptdist(n, 1.0 - y); end
500
- module_function :ptdist, :ptxXX_, :pt__X_, :pt___x, :ptx__x
501
-
502
-
503
- # F-distribution
504
- def f_x(n1, n2, x); 1.0 - fdist(n1, n2, x); end
505
- def fX_(n1, n2, x); fdist(n1, n2, x); end
506
- module_function :fdist, :fX_, :f_x
507
-
508
- # inverse of F-distribution
509
- def pf_x(n1, n2, x); pfdist(n1, n2, 1.0 - x); end
510
- def pfX_(n1, n2, x); pfdist(n1, n2, x); end
511
- module_function :pfdist, :pfX_, :pf_x
512
-
513
- # discrete distributions
514
- def binX_(n, p, x); bindist(n, p, x); end
515
- def bin_x(n, p, x); bindist(n, 1.0 - p, n - x); end
516
- module_function :bindens, :bindist, :binX_, :bin_x
517
-
518
- def poissonX_(m, x); poissondist(m, x); end
519
- def poisson_x(m, x); 1.0 - poissondist(m, x-1); end
520
- module_function :poissondens, :poissondist, :poissonX_, :poisson_x
521
- end
522
-
523
-
524
- if $0 == __FILE__
525
- if ARGV.empty?
526
- puts "Example:"
527
- puts " #$0 normaldist 0.01"
528
- puts " #$0 pf_x 2 3 0.01"
529
- exit
530
- end
531
- p Statistics2.send(ARGV[0], *ARGV[1..-1].map{|x| eval(x)})
532
- end