rubystats 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|