rubystats 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -0
- data/Manifest.txt +22 -0
- data/README.txt +109 -0
- data/Rakefile +19 -0
- data/examples/beta.rb +10 -12
- data/examples/binomial.rb +12 -10
- data/examples/failrate_vs_goal.rb +28 -0
- data/examples/fisher.rb +2 -6
- data/examples/norm.rb +10 -4
- data/lib/rubystats.rb +9 -0
- data/lib/rubystats/beta_distribution.rb +88 -0
- data/lib/rubystats/binomial_distribution.rb +195 -0
- data/lib/rubystats/fishers_exact_test.rb +171 -0
- data/lib/rubystats/modules.rb +742 -0
- data/lib/rubystats/normal_distribution.rb +114 -0
- data/lib/rubystats/probability_distribution.rb +131 -0
- data/{tests → test}/tc_beta.rb +4 -4
- data/{tests → test}/tc_binomial.rb +4 -4
- data/{tests → test}/tc_fisher.rb +2 -2
- data/test/tc_norm.rb +14 -0
- data/test/tc_require_all.rb +18 -0
- data/{tests → test}/ts_stats.rb +0 -0
- metadata +72 -51
- data/README +0 -9
- data/lib/beta_distribution.rb +0 -87
- data/lib/binomial_distribution.rb +0 -194
- data/lib/fishers_exact_test.rb +0 -171
- data/lib/modules/extra_math.rb +0 -7
- data/lib/modules/numerical_constants.rb +0 -17
- data/lib/modules/special_math.rb +0 -721
- data/lib/normal_distribution.rb +0 -114
- data/lib/probability_distribution.rb +0 -132
- data/tests/tc_norm.rb +0 -13
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'rubystats/probability_distribution'
|
2
|
+
# This class provides an object for encapsulating normal distributions
|
3
|
+
# Ported to Ruby from PHPMath class by Bryan Donovan
|
4
|
+
# Author:: Jaco van Kooten
|
5
|
+
# Author:: Paul Meagher
|
6
|
+
# Author:: Bryan Donovan (http://www.bryandonovan.com)
|
7
|
+
module Rubystats
|
8
|
+
class NormalDistribution < Rubystats::ProbabilityDistribution
|
9
|
+
include Rubystats::SpecialMath
|
10
|
+
|
11
|
+
# Constructs a normal distribution (defaults to zero mean and
|
12
|
+
# unity variance).
|
13
|
+
def initialize(mu=0.0, sigma=1.0)
|
14
|
+
@mean = mu
|
15
|
+
if sigma <= 0.0
|
16
|
+
return "error"
|
17
|
+
end
|
18
|
+
@stdev = sigma
|
19
|
+
@variance = sigma**2
|
20
|
+
@pdf_denominator = Sqrt2pi * Math.sqrt(@variance)
|
21
|
+
@cdf_denominator = Sqrt2 * Math.sqrt(@variance)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the mean of the distribution
|
25
|
+
def get_mean
|
26
|
+
return @mean
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the standard deviation of the distribution
|
30
|
+
def get_standard_deviation
|
31
|
+
return @stdev
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the variance of the distribution
|
35
|
+
def get_variance
|
36
|
+
return @variance
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Obtain single PDF value
|
42
|
+
# Returns the probability that a stochastic variable x has the value X,
|
43
|
+
# i.e. P(x=X)
|
44
|
+
def get_pdf(x)
|
45
|
+
Math.exp( -((x-@mean)**2) / (2 * @variance)) / @pdf_denominator
|
46
|
+
end
|
47
|
+
|
48
|
+
# Obtain single CDF value
|
49
|
+
# Returns the probability that a stochastic variable x is less than X,
|
50
|
+
# i.e. P(x<X)
|
51
|
+
def get_cdf(x)
|
52
|
+
complementary_error( -(x - @mean) / @cdf_denominator) / 2
|
53
|
+
end
|
54
|
+
|
55
|
+
# Obtain single inverse CDF value.
|
56
|
+
# returns the value X for which P(x<X).
|
57
|
+
def get_icdf(p)
|
58
|
+
check_range(p)
|
59
|
+
if p == 0.0
|
60
|
+
return -Max_value
|
61
|
+
end
|
62
|
+
if p == 1.0
|
63
|
+
return Max_value
|
64
|
+
end
|
65
|
+
if p == 0.5
|
66
|
+
return @mean
|
67
|
+
end
|
68
|
+
|
69
|
+
mean_save = @mean
|
70
|
+
var_save = @variance
|
71
|
+
pdf_D_save = @pdf_denominator
|
72
|
+
cdf_D_save = @cdf_denominator
|
73
|
+
@mean = 0.0
|
74
|
+
@variance = 1.0
|
75
|
+
@pdf_denominator = Math.sqrt(Two_pi)
|
76
|
+
@cdf_denominator = Sqrt2
|
77
|
+
x = find_root(p, 0.0, -100.0, 100.0)
|
78
|
+
#scale back
|
79
|
+
@mean = mean_save
|
80
|
+
@variance = var_save
|
81
|
+
@pdf_denominator = pdf_D_save
|
82
|
+
@cdf_denominator = cdf_D_save
|
83
|
+
return x * Math.sqrt(@variance) + @mean
|
84
|
+
end
|
85
|
+
|
86
|
+
# Uses the polar form of the Box-Muller transformation which
|
87
|
+
# is both faster and more robust numerically than basic Box-Muller
|
88
|
+
# transform. To speed up repeated RNG computations, two random values
|
89
|
+
# are computed after the while loop and the second one is saved and
|
90
|
+
# directly used if the method is called again.
|
91
|
+
# see http://www.taygeta.com/random/gaussian.html
|
92
|
+
# returns single normal deviate
|
93
|
+
def get_rng
|
94
|
+
if @use_last
|
95
|
+
y1 = @last
|
96
|
+
@use_last = false
|
97
|
+
else
|
98
|
+
w = 1
|
99
|
+
until w < 1.0 do
|
100
|
+
r1 = Kernel.rand
|
101
|
+
r2 = Kernel.rand
|
102
|
+
x1 = 2.0 * r1 - 1.0
|
103
|
+
x2 = 2.0 * r2 - 1.0
|
104
|
+
w = x1 * x1 * x2 * x2
|
105
|
+
end
|
106
|
+
w = Math.sqrt((-2.0 * Math.log(w)) / w)
|
107
|
+
y1 = x1 * w
|
108
|
+
@last = x2 * w
|
109
|
+
@use_last = true
|
110
|
+
end
|
111
|
+
return @mean + y1 * Math.sqrt(@variance)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'rubystats/modules'
|
2
|
+
|
3
|
+
module Rubystats
|
4
|
+
class ProbabilityDistribution
|
5
|
+
include Rubystats::NumericalConstants
|
6
|
+
include Rubystats::SpecialMath
|
7
|
+
include Rubystats::ExtraMath
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
end
|
11
|
+
|
12
|
+
def mean
|
13
|
+
get_mean
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_mean
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def pdf(x)
|
21
|
+
if x.class == Array
|
22
|
+
pdf_vals = []
|
23
|
+
for i in (0..x.length)
|
24
|
+
pdf_vals[i] = get_pdf(x[i])
|
25
|
+
end
|
26
|
+
return pdf_vals
|
27
|
+
else
|
28
|
+
return get_pdf(x)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_pdf(x)
|
33
|
+
end
|
34
|
+
|
35
|
+
def cdf(x)
|
36
|
+
if x.class == Array
|
37
|
+
cdf_vals = []
|
38
|
+
for i in (0...x.size)
|
39
|
+
cdf_vals[i] = get_cdf(x[i])
|
40
|
+
end
|
41
|
+
return cdf_vals
|
42
|
+
else
|
43
|
+
return get_cdf(x)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_cdf(x)
|
48
|
+
end
|
49
|
+
|
50
|
+
def icdf(p)
|
51
|
+
if p.class == Array
|
52
|
+
inv_vals = []
|
53
|
+
for i in (0..p.length)
|
54
|
+
inv_vals[i] = get_icdf(p[i])
|
55
|
+
end
|
56
|
+
return inv_vals
|
57
|
+
else
|
58
|
+
return get_icdf(p)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_icdf(p)
|
63
|
+
end
|
64
|
+
|
65
|
+
def rng(n=1)
|
66
|
+
if n < 1
|
67
|
+
return "Number of random numbers to return must be 1 or greater"
|
68
|
+
end
|
69
|
+
if (n > 1)
|
70
|
+
rnd_vals = []
|
71
|
+
for i in (0..n)
|
72
|
+
rnd_vals[i] = get_rng()
|
73
|
+
end
|
74
|
+
return rnd_vals
|
75
|
+
else
|
76
|
+
return get_rng()
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def get_rng()
|
81
|
+
end
|
82
|
+
|
83
|
+
def check_range(x, lo=0.0, hi=1.0)
|
84
|
+
if (x < lo) || (x > hi)
|
85
|
+
return "error"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_factorial(n)
|
90
|
+
if n <= 1
|
91
|
+
return 1
|
92
|
+
else
|
93
|
+
return n * get_factorial(n-1)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def find_root (prob, guess, x_lo, x_hi)
|
98
|
+
accuracy = 1.0e-10
|
99
|
+
max_iteration = 150
|
100
|
+
x = guess
|
101
|
+
x_new = guess
|
102
|
+
error = 0.0
|
103
|
+
pdf = 0.0
|
104
|
+
dx = 1000.0
|
105
|
+
i = 0
|
106
|
+
while ( dx.abs > accuracy && (i += 1) < max_iteration )
|
107
|
+
#Apply Newton-Raphson step
|
108
|
+
error = cdf(x) - prob
|
109
|
+
if error < 0.0
|
110
|
+
x_lo = x
|
111
|
+
else
|
112
|
+
x_hi = x
|
113
|
+
end
|
114
|
+
pdf = pdf(x)
|
115
|
+
if pdf != 0.0
|
116
|
+
dx = error / pdf
|
117
|
+
x_new = x -dx
|
118
|
+
end
|
119
|
+
# If the NR fails to converge (which for example may be the
|
120
|
+
# case if the initial guess is too rough) we apply a bisection
|
121
|
+
# step to determine a more narrow interval around the root.
|
122
|
+
if x_new < x_lo || x_new > x_hi || pdf == 0.0
|
123
|
+
x_new = (x_lo + x_hi) / 2.0
|
124
|
+
dx = x_new - x
|
125
|
+
end
|
126
|
+
x = x_new
|
127
|
+
end
|
128
|
+
return x
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
data/{tests → test}/tc_beta.rb
RENAMED
@@ -1,12 +1,12 @@
|
|
1
1
|
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
2
|
require 'test/unit'
|
3
|
-
require 'beta_distribution'
|
3
|
+
require 'rubystats/beta_distribution'
|
4
4
|
|
5
5
|
class TestBeta < Test::Unit::TestCase
|
6
6
|
def test_simple
|
7
7
|
p = 12
|
8
8
|
q = 59
|
9
|
-
beta = BetaDistribution.new(p,q)
|
9
|
+
beta = Rubystats::BetaDistribution.new(p,q)
|
10
10
|
assert_equal("0.169014084507042", beta.mean.to_s)
|
11
11
|
assert_equal("0.0441664031038187", beta.standard_deviation.to_s)
|
12
12
|
assert_equal("6.26075815849967", beta.pdf(0.2).to_s)
|
@@ -61,7 +61,7 @@ class TestBeta < Test::Unit::TestCase
|
|
61
61
|
lcl=0
|
62
62
|
else
|
63
63
|
q=trials-p+1
|
64
|
-
bin= BetaDistribution.new(p,q)
|
64
|
+
bin= Rubystats::BetaDistribution.new(p,q)
|
65
65
|
lcl=bin.icdf(alpha)
|
66
66
|
end
|
67
67
|
return lcl
|
@@ -70,7 +70,7 @@ class TestBeta < Test::Unit::TestCase
|
|
70
70
|
def get_upper_limit(trials,alpha,p)
|
71
71
|
q=trials-p
|
72
72
|
p=p+1
|
73
|
-
bin= BetaDistribution.new(p,q)
|
73
|
+
bin= Rubystats::BetaDistribution.new(p,q)
|
74
74
|
ucl=bin.icdf(1-alpha)
|
75
75
|
return ucl
|
76
76
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
2
|
require 'test/unit'
|
3
|
-
require 'binomial_distribution'
|
3
|
+
require 'rubystats/binomial_distribution'
|
4
4
|
|
5
5
|
class TestBinomial < Test::Unit::TestCase
|
6
6
|
def test_simple
|
@@ -8,14 +8,14 @@ class TestBinomial < Test::Unit::TestCase
|
|
8
8
|
f = 7
|
9
9
|
p = 0.05
|
10
10
|
|
11
|
-
bin = BinomialDistribution.new(t,p)
|
11
|
+
bin = Rubystats::BinomialDistribution.new(t,p)
|
12
12
|
cdf = bin.cdf(f)
|
13
13
|
pdf = bin.pdf(f)
|
14
14
|
mean = bin.mean
|
15
15
|
inv_cdf = bin.icdf(cdf)
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
assert_in_delta(0.10602553736479, pdf, 0.00000000000001 )
|
18
|
+
assert_in_delta(0.87203952137960, cdf, 0.00000000000001)
|
19
19
|
assert_equal("5.0",mean.to_s)
|
20
20
|
assert_equal(f,inv_cdf)
|
21
21
|
end
|
data/{tests → test}/tc_fisher.rb
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
2
|
require 'test/unit'
|
3
|
-
require 'fishers_exact_test'
|
3
|
+
require 'rubystats/fishers_exact_test'
|
4
4
|
|
5
5
|
class TestFisher < Test::Unit::TestCase
|
6
6
|
def test_simple
|
@@ -10,7 +10,7 @@ class TestFisher < Test::Unit::TestCase
|
|
10
10
|
f2 = 10
|
11
11
|
t1 = tested1 - f1
|
12
12
|
t2 = tested2 - f2
|
13
|
-
fet = FishersExactTest.new
|
13
|
+
fet = Rubystats::FishersExactTest.new
|
14
14
|
fisher = fet.calculate(t1,t2,f1,f2)
|
15
15
|
|
16
16
|
assert_equal("0.188301375769922",fisher[:left].to_s)
|
data/test/tc_norm.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rubystats/normal_distribution'
|
4
|
+
|
5
|
+
class TestNormal < Test::Unit::TestCase
|
6
|
+
def test_simple
|
7
|
+
|
8
|
+
norm = Rubystats::NormalDistribution.new(10,2)
|
9
|
+
cdf = norm.cdf(11)
|
10
|
+
|
11
|
+
assert_equal("0.691462461274013",cdf.to_s)
|
12
|
+
assert_not_nil(norm.rng)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
|
3
|
+
#
|
4
|
+
# test that we can use old api that wasn't namespaced
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'test/unit'
|
8
|
+
require 'rubystats'
|
9
|
+
|
10
|
+
class TestNormal < Test::Unit::TestCase
|
11
|
+
def test_simple
|
12
|
+
norm = NormalDistribution.new(10,2)
|
13
|
+
cdf = norm.cdf(11)
|
14
|
+
|
15
|
+
assert_equal("0.691462461274013",cdf.to_s)
|
16
|
+
assert_not_nil(norm.rng)
|
17
|
+
end
|
18
|
+
end
|
data/{tests → test}/ts_stats.rb
RENAMED
File without changes
|
metadata
CHANGED
@@ -1,64 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.0
|
3
|
-
specification_version: 1
|
4
2
|
name: rubystats
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-05-18 00:00:00 -07:00
|
8
|
-
summary: Classes for statistical calculations, e.g., binomial, beta, and normal distributions with PDF, CDF and inverse CDF (all ported from PHPMath) as well as Fisher's Exact Test
|
9
|
-
require_paths:
|
10
|
-
- lib
|
11
|
-
email: Bryandonovan@myrealbox.com
|
12
|
-
homepage: http://www.bryandonovan.com
|
13
|
-
rubyforge_project:
|
14
|
-
description:
|
15
|
-
autorequire:
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: true
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
4
|
+
version: 0.2.0
|
25
5
|
platform: ruby
|
26
|
-
signing_key:
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
6
|
authors:
|
30
|
-
- Bryan Donovan
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
- lib/fishers_exact_test.rb
|
35
|
-
- lib/modules
|
36
|
-
- lib/normal_distribution.rb
|
37
|
-
- lib/probability_distribution.rb
|
38
|
-
- lib/modules/extra_math.rb
|
39
|
-
- lib/modules/numerical_constants.rb
|
40
|
-
- lib/modules/special_math.rb
|
41
|
-
- tests/tc_beta.rb
|
42
|
-
- tests/tc_binomial.rb
|
43
|
-
- tests/tc_fisher.rb
|
44
|
-
- tests/tc_norm.rb
|
45
|
-
- tests/ts_stats.rb
|
46
|
-
- examples/beta.rb
|
47
|
-
- examples/binomial.rb
|
48
|
-
- examples/fisher.rb
|
49
|
-
- examples/norm.rb
|
50
|
-
- README
|
51
|
-
test_files:
|
52
|
-
- tests/ts_stats.rb
|
53
|
-
rdoc_options: []
|
7
|
+
- Bryan Donovan - http://www.bryandonovan.com
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
54
11
|
|
55
|
-
|
56
|
-
|
12
|
+
date: 2008-04-15 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.5.1
|
23
|
+
version:
|
24
|
+
description: Ruby Stats is a port of the statistics libraries from PHPMath. Probability distributions include binomial, beta, and normal distributions with PDF, CDF and inverse CDF as well as Fisher's Exact Test.
|
25
|
+
email: b.dondo+rubyforge@gmail.com
|
57
26
|
executables: []
|
58
27
|
|
59
28
|
extensions: []
|
60
29
|
|
30
|
+
extra_rdoc_files:
|
31
|
+
- History.txt
|
32
|
+
- Manifest.txt
|
33
|
+
- README.txt
|
34
|
+
files:
|
35
|
+
- History.txt
|
36
|
+
- Manifest.txt
|
37
|
+
- README.txt
|
38
|
+
- Rakefile
|
39
|
+
- examples/beta.rb
|
40
|
+
- examples/binomial.rb
|
41
|
+
- examples/failrate_vs_goal.rb
|
42
|
+
- examples/fisher.rb
|
43
|
+
- examples/norm.rb
|
44
|
+
- lib/rubystats.rb
|
45
|
+
- lib/rubystats/beta_distribution.rb
|
46
|
+
- lib/rubystats/binomial_distribution.rb
|
47
|
+
- lib/rubystats/fishers_exact_test.rb
|
48
|
+
- lib/rubystats/modules.rb
|
49
|
+
- lib/rubystats/normal_distribution.rb
|
50
|
+
- lib/rubystats/probability_distribution.rb
|
51
|
+
- test/tc_beta.rb
|
52
|
+
- test/tc_binomial.rb
|
53
|
+
- test/tc_fisher.rb
|
54
|
+
- test/tc_norm.rb
|
55
|
+
- test/tc_require_all.rb
|
56
|
+
- test/ts_stats.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://rubyforge.org/projects/rubystats/
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options:
|
61
|
+
- --main
|
62
|
+
- README.txt
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
61
77
|
requirements: []
|
62
78
|
|
63
|
-
|
79
|
+
rubyforge_project: rubystats
|
80
|
+
rubygems_version: 1.1.0
|
81
|
+
signing_key:
|
82
|
+
specification_version: 2
|
83
|
+
summary: Port of PHPMath to Ruby
|
84
|
+
test_files: []
|
64
85
|
|