distribution 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/.autotest +23 -0
- data/History.txt +3 -0
- data/Manifest.txt +39 -0
- data/README.txt +71 -0
- data/Rakefile +19 -0
- data/bin/distribution +3 -0
- data/lib/distribution.rb +148 -0
- data/lib/distribution/bivariatenormal.rb +25 -0
- data/lib/distribution/bivariatenormal/gsl.rb +11 -0
- data/lib/distribution/bivariatenormal/ruby.rb +281 -0
- data/lib/distribution/bivariatenormal/statistics2.rb +0 -0
- data/lib/distribution/chisquare.rb +29 -0
- data/lib/distribution/chisquare/gsl.rb +27 -0
- data/lib/distribution/chisquare/ruby.rb +85 -0
- data/lib/distribution/chisquare/statistics2.rb +21 -0
- data/lib/distribution/f.rb +28 -0
- data/lib/distribution/f/gsl.rb +28 -0
- data/lib/distribution/f/ruby.rb +117 -0
- data/lib/distribution/f/statistics2.rb +26 -0
- data/lib/distribution/math_extension.rb +72 -0
- data/lib/distribution/normal.rb +36 -0
- data/lib/distribution/normal/gsl.rb +24 -0
- data/lib/distribution/normal/ruby.rb +99 -0
- data/lib/distribution/normal/statistics2.rb +14 -0
- data/lib/distribution/normalmultivariate.rb +73 -0
- data/lib/distribution/t.rb +27 -0
- data/lib/distribution/t/gsl.rb +29 -0
- data/lib/distribution/t/ruby.rb +105 -0
- data/lib/distribution/t/statistics2.rb +28 -0
- data/spec/bivariatenormal_spec.rb +63 -0
- data/spec/chisquare_spec.rb +89 -0
- data/spec/distribution_spec.rb +19 -0
- data/spec/f_spec.rb +107 -0
- data/spec/normal_spec.rb +105 -0
- data/spec/shorthand_function.rb +6 -0
- data/spec/shorthand_spec.rb +14 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/t_spec.rb +98 -0
- metadata +160 -0
- metadata.gz.sig +1 -0
File without changes
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'distribution/chisquare/ruby'
|
2
|
+
require 'distribution/chisquare/gsl'
|
3
|
+
require 'distribution/chisquare/statistics2'
|
4
|
+
module Distribution
|
5
|
+
# Calculate cdf and inverse cdf for Chi Square Distribution.
|
6
|
+
#
|
7
|
+
module ChiSquare
|
8
|
+
extend Distributable
|
9
|
+
SHORTHAND='chisq'
|
10
|
+
create_distribution_methods
|
11
|
+
|
12
|
+
##
|
13
|
+
# :singleton-method: pdf(x)
|
14
|
+
# Returns PDF of of Chi-squared distribution
|
15
|
+
# with +k+ degrees of freedom
|
16
|
+
|
17
|
+
|
18
|
+
##
|
19
|
+
# :singleton-method: cdf(x,k)
|
20
|
+
# Returns the integral of Chi-squared distribution
|
21
|
+
# with +k+ degrees of freedom over [0, +x+]
|
22
|
+
|
23
|
+
##
|
24
|
+
# :singleton-method: p_value(qn, k)
|
25
|
+
# Return the P-value of the corresponding integral +qn+ with
|
26
|
+
# +k+ degrees of freedom
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Distribution
|
2
|
+
module ChiSquare
|
3
|
+
module GSL_
|
4
|
+
class << self
|
5
|
+
def rng(k,seed=nil)
|
6
|
+
|
7
|
+
end
|
8
|
+
def pdf(x,k)
|
9
|
+
GSL::Ran::chisq_pdf(x,k)
|
10
|
+
end
|
11
|
+
# Return the P-value of the corresponding integral with
|
12
|
+
# k degrees of freedom
|
13
|
+
def p_value(pr,k)
|
14
|
+
GSL::Cdf::chisq_Pinv(pr,k)
|
15
|
+
end
|
16
|
+
# Chi-square cumulative distribution function (cdf).
|
17
|
+
#
|
18
|
+
# Returns the integral of Chi-squared distribution
|
19
|
+
# with k degrees of freedom over [0, x]
|
20
|
+
#
|
21
|
+
def cdf(x, k)
|
22
|
+
GSL::Cdf::chisq_P(x,k)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Distribution
|
2
|
+
module ChiSquare
|
3
|
+
module Ruby_
|
4
|
+
class << self
|
5
|
+
|
6
|
+
include Distribution::MathExtension
|
7
|
+
|
8
|
+
def pdf(x,n)
|
9
|
+
if n == 1
|
10
|
+
1.0/Math.sqrt(2 * Math::PI * x) * Math::E**(-x/2.0)
|
11
|
+
elsif n == 2
|
12
|
+
0.5 * Math::E**(-x/2.0)
|
13
|
+
else
|
14
|
+
n = n.to_f
|
15
|
+
n2 = n/2
|
16
|
+
x = x.to_f
|
17
|
+
1.0 / 2**n2 / gamma(n2) * x**(n2 - 1.0) * Math.exp(-x/2.0)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# CDF Inverse over [x, \infty)
|
23
|
+
# Pr([x, \infty)) = y -> x
|
24
|
+
def pchi2(n, y)
|
25
|
+
if n == 1
|
26
|
+
|
27
|
+
w = Distribution::Normal.p_value(1 - y/2) # = p1.0-Distribution::Normal.cdf(y/2)
|
28
|
+
w * w
|
29
|
+
elsif n == 2
|
30
|
+
# v = (1.0 / y - 1.0) / 33.0
|
31
|
+
# newton_a(y, v) {|x| [q_chi2(n, x), -chi2dens(n, x)] }
|
32
|
+
-2.0 * Math.log(y)
|
33
|
+
else
|
34
|
+
eps = 1.0e-5
|
35
|
+
v = 0.0
|
36
|
+
s = 10.0
|
37
|
+
loop do
|
38
|
+
v += s
|
39
|
+
if s <= eps then break end
|
40
|
+
if (qe = q_chi2(n, v) - y) == 0.0 then break end
|
41
|
+
if qe < 0.0
|
42
|
+
v -= s
|
43
|
+
s /= 10.0 #/
|
44
|
+
end
|
45
|
+
end
|
46
|
+
v
|
47
|
+
end
|
48
|
+
end
|
49
|
+
def p_value(pr,k)
|
50
|
+
pchi2(k, 1.0-pr)
|
51
|
+
end
|
52
|
+
def cdf(x,k)
|
53
|
+
1.0-q_chi2(k,x)
|
54
|
+
end
|
55
|
+
|
56
|
+
# chi-square distribution ([1])
|
57
|
+
# Integral over [x, \infty)
|
58
|
+
def q_chi2(df, chi2)
|
59
|
+
chi2 = chi2.to_f
|
60
|
+
if (df & 1) != 0
|
61
|
+
chi = Math.sqrt(chi2)
|
62
|
+
if (df == 1) then return 2 * (1.0-Distribution::Normal.cdf(chi)); end
|
63
|
+
s = t = chi * Math.exp(-0.5 * chi2) / SQ2PI
|
64
|
+
k = 3
|
65
|
+
while k < df
|
66
|
+
t *= chi2 / k; s += t;
|
67
|
+
k += 2
|
68
|
+
end
|
69
|
+
2 * (1.0-(Distribution::Normal.cdf(chi)) + s)
|
70
|
+
else
|
71
|
+
s = t = Math.exp(-0.5 * chi2)
|
72
|
+
k = 2
|
73
|
+
while k < df
|
74
|
+
t *= chi2 / k; s += t;
|
75
|
+
k += 2
|
76
|
+
end
|
77
|
+
s
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Distribution
|
2
|
+
module ChiSquare
|
3
|
+
module Statistics2_
|
4
|
+
class << self
|
5
|
+
# Return the P-value of the corresponding integral with
|
6
|
+
# k degrees of freedom
|
7
|
+
def p_value(pr,k)
|
8
|
+
Statistics2.pchi2X_(k.to_i, pr)
|
9
|
+
end
|
10
|
+
# Chi-square cumulative distribution function (cdf).
|
11
|
+
#
|
12
|
+
# Returns the integral of Chi-squared distribution
|
13
|
+
# with k degrees of freedom over [0, x]
|
14
|
+
#
|
15
|
+
def cdf(x, k)
|
16
|
+
Statistics2.chi2dist(k.to_i,x)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'distribution/f/ruby'
|
2
|
+
require 'distribution/f/gsl'
|
3
|
+
require 'distribution/f/statistics2'
|
4
|
+
module Distribution
|
5
|
+
# Calculate cdf and inverse cdf for Chi Square Distribution.
|
6
|
+
#
|
7
|
+
module F
|
8
|
+
SHORTHAND='f'
|
9
|
+
extend Distributable
|
10
|
+
create_distribution_methods
|
11
|
+
|
12
|
+
##
|
13
|
+
# :singleton-method: pdf(x,k1,k2)
|
14
|
+
# Returns the PDF of F distribution
|
15
|
+
# with +k1+ and +k2+ degrees of freedom over [0, +x+]
|
16
|
+
|
17
|
+
##
|
18
|
+
# :singleton-method: p_value(qn, k1, k2)
|
19
|
+
# Return the P-value of the corresponding integral +qn+ with
|
20
|
+
# +k1+ and +k2+ degrees of freedom
|
21
|
+
|
22
|
+
##
|
23
|
+
# :singleton-method: cdf(x,k1,k2)
|
24
|
+
# Returns the integral of F distribution
|
25
|
+
# with +k1+ and +k2+ degrees of freedom over [0, +x+]
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Distribution
|
2
|
+
module F
|
3
|
+
module GSL_
|
4
|
+
class << self
|
5
|
+
def pdf(x,k1,k2)
|
6
|
+
GSL::Ran.fdist_pdf(x,k1,k2)
|
7
|
+
end
|
8
|
+
# Return the P-value of the corresponding integral with
|
9
|
+
# k degrees of freedom
|
10
|
+
#
|
11
|
+
# Distribution::F.p_value(0.95,1,2)
|
12
|
+
def p_value(pr,k1,k2)
|
13
|
+
GSL::Cdf.fdist_Pinv(pr,k1,k2)
|
14
|
+
end
|
15
|
+
# F cumulative distribution function (cdf).
|
16
|
+
#
|
17
|
+
# Returns the integral of F-distribution
|
18
|
+
# with k1 and k2 degrees of freedom
|
19
|
+
# over [0, x].
|
20
|
+
# Distribution::F.cdf(20,3,2)
|
21
|
+
#
|
22
|
+
def cdf(x, k1, k2)
|
23
|
+
GSL::Cdf.fdist_P(x.to_f,k1,k2)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Distribution
|
2
|
+
module F
|
3
|
+
module Ruby_
|
4
|
+
class << self
|
5
|
+
|
6
|
+
def c_pdf(f,df)
|
7
|
+
Distribution::ChiSquare.pdf(f,df)
|
8
|
+
end
|
9
|
+
def pdf(x,d1,d2)
|
10
|
+
Math.sqrt(((d1*x)**d1*(d2**d2)).quo((d1*x+d2)**(d1+d2))).quo( x*Math.beta(d1/2.0, d2/2.0))
|
11
|
+
end
|
12
|
+
# F-distribution ([1])
|
13
|
+
# Integral over [x, \infty)
|
14
|
+
def q_f(df1, df2, f)
|
15
|
+
if (f <= 0.0) then return 1.0; end
|
16
|
+
if (df1 % 2 != 0 && df2 % 2 == 0)
|
17
|
+
return 1.0 - q_f(df2, df1, 1.0 / f)
|
18
|
+
end
|
19
|
+
cos2 = 1.0 / (1.0 + df1.to_f * f / df2.to_f)
|
20
|
+
sin2 = 1.0 - cos2
|
21
|
+
|
22
|
+
if (df1 % 2 == 0)
|
23
|
+
prob = cos2 ** (df2.to_f / 2.0)
|
24
|
+
temp = prob
|
25
|
+
i = 2
|
26
|
+
while i < df1
|
27
|
+
temp *= (df2.to_f + i - 2) * sin2 / i
|
28
|
+
prob += temp
|
29
|
+
i += 2
|
30
|
+
end
|
31
|
+
return prob
|
32
|
+
end
|
33
|
+
prob = Math.atan(Math.sqrt(df2.to_f / (df1.to_f * f)))
|
34
|
+
temp = Math.sqrt(sin2 * cos2)
|
35
|
+
i = 3
|
36
|
+
while i <= df1
|
37
|
+
prob += temp
|
38
|
+
temp *= (i - 1).to_f * sin2 / i.to_f;
|
39
|
+
i += 2.0
|
40
|
+
end
|
41
|
+
temp *= df1.to_f
|
42
|
+
i = 3
|
43
|
+
while i <= df2
|
44
|
+
prob -= temp
|
45
|
+
temp *= (df1.to_f + i - 2) * cos2 / i.to_f
|
46
|
+
i += 2
|
47
|
+
end
|
48
|
+
prob * 2.0 / Math::PI
|
49
|
+
end
|
50
|
+
|
51
|
+
# inverse of F-distribution ([2])
|
52
|
+
def pfsub(x, y, z)
|
53
|
+
(Math.sqrt(z) - y) / x / 2.0
|
54
|
+
end
|
55
|
+
|
56
|
+
# Inverse CDF
|
57
|
+
# [x, \infty)
|
58
|
+
def pf(q, n1, n2)
|
59
|
+
if(q < 0.0 || q > 1.0 || n1 < 1 || n2 < 1)
|
60
|
+
$stderr.printf("Error : Illegal parameter in pf()!\n")
|
61
|
+
return 0.0
|
62
|
+
end
|
63
|
+
|
64
|
+
if n1 <= 240 || n2 <= 240
|
65
|
+
eps = 1.0e-5
|
66
|
+
if(n2 == 1) then eps = 1.0e-4 end
|
67
|
+
fw = 0.0
|
68
|
+
s = 1000.0
|
69
|
+
loop do
|
70
|
+
fw += s
|
71
|
+
if s <= eps then return fw end
|
72
|
+
if (qe = q_f(n1, n2, fw) - q) == 0.0 then return fw end
|
73
|
+
if qe < 0.0
|
74
|
+
fw -= s
|
75
|
+
s /= 10.0 #/
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
eps = 1.0e-6
|
81
|
+
qn = q
|
82
|
+
if q < 0.5 then qn = 1.0 - q
|
83
|
+
u = pnorm(qn)
|
84
|
+
w1 = 2.0 / n1 / 9.0
|
85
|
+
w2 = 2.0 / n2 / 9.0
|
86
|
+
w3 = 1.0 - w1
|
87
|
+
w4 = 1.0 - w2
|
88
|
+
u2 = u * u
|
89
|
+
a = w4 * w4 - u2 * w2
|
90
|
+
b = -2. * w3 * w4
|
91
|
+
c = w3 * w3 - u2 * w1
|
92
|
+
d = b * b - 4 * a * c
|
93
|
+
if(d < 0.0)
|
94
|
+
fw = pfsub(a, b, 0.0)
|
95
|
+
else
|
96
|
+
if(a.abs > eps)
|
97
|
+
fw = pfsub(a, b, d)
|
98
|
+
else
|
99
|
+
if(b.abs > eps) then return -c / b end
|
100
|
+
fw = pfsub(a, b, 0.0)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
fw * fw * fw
|
104
|
+
end
|
105
|
+
end
|
106
|
+
# F-distribution interface
|
107
|
+
def cdf(f,n1, n2)
|
108
|
+
1.0 - q_f(n1, n2, f)
|
109
|
+
end
|
110
|
+
def p_value(y, n1, n2)
|
111
|
+
pf(1.0 - y, n1, n2)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Distribution
|
2
|
+
module F
|
3
|
+
module Statistics2_
|
4
|
+
class << self
|
5
|
+
# Return the P-value of the corresponding integral with
|
6
|
+
# k degrees of freedom
|
7
|
+
#
|
8
|
+
# Distribution::F.p_value(0.95,1,2)
|
9
|
+
# Statistics2 have some problem with extreme values
|
10
|
+
def p_value(pr,k1,k2)
|
11
|
+
Statistics2.pfdist(k1,k2, pr)
|
12
|
+
end
|
13
|
+
# F cumulative distribution function (cdf).
|
14
|
+
#
|
15
|
+
# Returns the integral of F-distribution
|
16
|
+
# with k1 and k2 degrees of freedom
|
17
|
+
# over [0, x].
|
18
|
+
# Distribution::F.cdf(20,3,2)
|
19
|
+
#
|
20
|
+
def cdf(x, k1, k2)
|
21
|
+
Statistics2.fdist(k1, k2,x)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# Useful additions to Math
|
2
|
+
module Distribution
|
3
|
+
module MathExtension
|
4
|
+
# Factorial for n
|
5
|
+
def factorial(n)
|
6
|
+
sum=1
|
7
|
+
2.upto(n) do |i|
|
8
|
+
sum*=n
|
9
|
+
end
|
10
|
+
sum
|
11
|
+
end
|
12
|
+
|
13
|
+
# Beta function.
|
14
|
+
# Source:
|
15
|
+
# * http://mathworld.wolfram.com/BetaFunction.html
|
16
|
+
def beta(x,y)
|
17
|
+
(gamma(x)*gamma(y)).quo(gamma(x+y))
|
18
|
+
end
|
19
|
+
|
20
|
+
LOG_2PI = Math.log(2 * Math::PI)# log(2PI)
|
21
|
+
N = 8
|
22
|
+
B0 = 1.0
|
23
|
+
B1 = -1.0 / 2.0
|
24
|
+
B2 = 1.0 / 6.0
|
25
|
+
B4 = -1.0 / 30.0
|
26
|
+
B6 = 1.0 / 42.0
|
27
|
+
B8 = -1.0 / 30.0
|
28
|
+
B10 = 5.0 / 66.0
|
29
|
+
B12 = -691.0 / 2730.0
|
30
|
+
B14 = 7.0 / 6.0
|
31
|
+
B16 = -3617.0 / 510.0
|
32
|
+
# From statistics2
|
33
|
+
def loggamma(x)
|
34
|
+
v = 1.0
|
35
|
+
while (x < N)
|
36
|
+
v *= x
|
37
|
+
x += 1.0
|
38
|
+
end
|
39
|
+
w = 1.0 / (x * x)
|
40
|
+
ret = B16 / (16 * 15)
|
41
|
+
ret = ret * w + B14 / (14 * 13)
|
42
|
+
ret = ret * w + B12 / (12 * 11)
|
43
|
+
ret = ret * w + B10 / (10 * 9)
|
44
|
+
ret = ret * w + B8 / ( 8 * 7)
|
45
|
+
ret = ret * w + B6 / ( 6 * 5)
|
46
|
+
ret = ret * w + B4 / ( 4 * 3)
|
47
|
+
ret = ret * w + B2 / ( 2 * 1)
|
48
|
+
ret = ret / x + 0.5 * LOG_2PI - Math.log(v) - x + (x - 0.5) * Math.log(x)
|
49
|
+
ret
|
50
|
+
end
|
51
|
+
# Gamma function.
|
52
|
+
# From statistics2
|
53
|
+
def gamma(x)
|
54
|
+
if (x < 0.0)
|
55
|
+
return Math::PI / (Math.sin(Math.PI * x) * Math.exp(loggamma(1 - x))) #/
|
56
|
+
end
|
57
|
+
Math.exp(loggamma(x))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module Math
|
63
|
+
include Distribution::MathExtension
|
64
|
+
module_function :factorial, :beta, :gamma
|
65
|
+
end
|
66
|
+
|
67
|
+
# Necessary on Ruby 1.9
|
68
|
+
module CMath # :nodoc:
|
69
|
+
include Distribution::MathExtension
|
70
|
+
module_function :factorial, :beta, :gamma
|
71
|
+
end
|
72
|
+
|