rubystats 0.2.6 → 0.3.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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/README.rdoc +17 -6
- data/examples/uniform.rb +14 -0
- data/lib/rubystats.rb +29 -0
- data/lib/rubystats/beta_distribution.rb +4 -0
- data/lib/rubystats/binomial_distribution.rb +42 -131
- data/lib/rubystats/cauchy_distribution.rb +50 -0
- data/lib/rubystats/exponential_distribution.rb +2 -2
- data/lib/rubystats/gamma_distribution.rb +70 -0
- data/lib/rubystats/lognormal_distribution.rb +59 -0
- data/lib/rubystats/modules.rb +6 -0
- data/lib/rubystats/multivariate_normal_distribution.rb +73 -0
- data/lib/rubystats/normal_distribution.rb +2 -2
- data/lib/rubystats/poisson_distribution.rb +78 -0
- data/lib/rubystats/probability_distribution.rb +3 -3
- data/lib/rubystats/student_t_distribution.rb +62 -0
- data/lib/rubystats/uniform_distribution.rb +70 -0
- data/lib/rubystats/version.rb +1 -1
- data/lib/rubystats/weibull_distribution.rb +56 -0
- data/test/tc_beta.rb +21 -0
- data/test/tc_binomial.rb +14 -0
- data/test/tc_cauchy.rb +39 -0
- data/test/tc_exponential.rb +10 -0
- data/test/tc_gamma.rb +39 -0
- data/test/tc_lnorm.rb +45 -0
- data/test/tc_multivariate_normal.rb +53 -0
- data/test/tc_norm.rb +11 -1
- data/test/tc_poisson.rb +35 -0
- data/test/tc_studentt.rb +43 -0
- data/test/tc_unif.rb +48 -0
- data/test/tc_weibull.rb +51 -0
- metadata +27 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 594c482d4bcbf6954516475851e5d8361eb171e6
|
4
|
+
data.tar.gz: 89bb13f0241a4a42439099c37d4f2500f64b8519
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 34a76aa78895d6fc605660d72b8e7602c1dd85150132b1bef2969c438cac22c1c91425cf1c3599b3202a43bc5a644444c31e30d9d181c8894cdfa2a70755da89
|
7
|
+
data.tar.gz: 12836502065954197f8c097060794f968d5845e9e9460c6ce175b91df04a569050f26a69855bee7803136661774c0aa39921aff2fe57f89b95de53ef4089782e
|
data/.travis.yml
CHANGED
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Rubystats
|
2
2
|
|
3
|
-
*
|
3
|
+
* https://github.com/phillbaker/rubystats
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
@@ -37,19 +37,30 @@
|
|
37
37
|
This is beta-quality software. It works well according to my tests, but the API may change and other features may be added.
|
38
38
|
|
39
39
|
== FEATURES:
|
40
|
-
Classes for distributions:
|
40
|
+
Classes for continuous distributions:
|
41
41
|
|
42
|
-
* Normal
|
43
|
-
* Binomial
|
44
42
|
* Beta
|
43
|
+
* Cauchy
|
45
44
|
* Exponential
|
45
|
+
* Gamma
|
46
|
+
* Lognormal
|
47
|
+
* Multivariate Normal
|
48
|
+
* Normal
|
49
|
+
* Student t
|
50
|
+
* Uniform
|
51
|
+
* Weibull
|
52
|
+
|
53
|
+
Classes for discrete distributions:
|
54
|
+
|
55
|
+
* Binomial
|
56
|
+
* Poisson
|
46
57
|
|
47
58
|
Also includes Fisher's Exact Test
|
48
59
|
|
49
60
|
== SYNOPSIS:
|
50
61
|
=== Example: normal distribution with mean of 10 and standard deviation of 2
|
51
62
|
|
52
|
-
norm = Rubystats::NormalDistribution.new(10, 2)
|
63
|
+
norm = Rubystats::NormalDistribution.new(10.0, 2.0)
|
53
64
|
cdf = norm.cdf(11)
|
54
65
|
pdf = norm.pdf(11)
|
55
66
|
puts "CDF(11): #{cdf}"
|
@@ -57,7 +68,7 @@ Also includes Fisher's Exact Test
|
|
57
68
|
|
58
69
|
Output:
|
59
70
|
CDF(11): 0.691462461274013
|
60
|
-
PDF(11): 0.
|
71
|
+
PDF(11): 0.17603266338214973
|
61
72
|
|
62
73
|
=== Example: get some random numbers from a normal distribution
|
63
74
|
|
data/examples/uniform.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'rubystats/uniform_distribution'
|
3
|
+
|
4
|
+
#uniform distribution with lower and upper bound of 0.0 and 1.0
|
5
|
+
unif = Rubystats::UniformDistribution.new(1.0, 6.0)
|
6
|
+
cdf = unif.cdf(2.5)
|
7
|
+
pdf = unif.pdf(2.5)
|
8
|
+
puts "CDF(2.5): #{cdf}"
|
9
|
+
puts "PDF(2.5): #{pdf}"
|
10
|
+
|
11
|
+
puts "Random numbers from the uniform distribution:"
|
12
|
+
10.times do
|
13
|
+
puts unif.rng
|
14
|
+
end
|
data/lib/rubystats.rb
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
require 'rubystats/normal_distribution'
|
2
2
|
require 'rubystats/binomial_distribution'
|
3
|
+
require 'rubystats/poisson_distribution'
|
3
4
|
require 'rubystats/beta_distribution'
|
4
5
|
require 'rubystats/fishers_exact_test'
|
5
6
|
require 'rubystats/exponential_distribution'
|
7
|
+
require 'rubystats/uniform_distribution'
|
8
|
+
require 'rubystats/lognormal_distribution'
|
9
|
+
require 'rubystats/student_t_distribution'
|
10
|
+
require 'rubystats/weibull_distribution'
|
11
|
+
require 'rubystats/cauchy_distribution'
|
12
|
+
require 'rubystats/gamma_distribution'
|
13
|
+
require 'rubystats/multivariate_normal_distribution'
|
6
14
|
require 'rubystats/version'
|
7
15
|
|
8
16
|
module Rubystats
|
@@ -10,6 +18,27 @@ end
|
|
10
18
|
|
11
19
|
NormalDistribution = Rubystats::NormalDistribution
|
12
20
|
BinomialDistribution = Rubystats::BinomialDistribution
|
21
|
+
PoissonDistribution = Rubystats::PoissonDistribution
|
13
22
|
BetaDistribution = Rubystats::BetaDistribution
|
14
23
|
FishersExactTest = Rubystats::FishersExactTest
|
15
24
|
ExponentialDistribution = Rubystats::ExponentialDistribution
|
25
|
+
UniformDistribution = Rubystats::UniformDistribution
|
26
|
+
LognormalDistribution = Rubystats::LognormalDistribution
|
27
|
+
StudentTDistribution = Rubystats::StudentTDistribution
|
28
|
+
WeibullDistribution = Rubystats::WeibullDistribution
|
29
|
+
CauchyDistribution = Rubystats::CauchyDistribution
|
30
|
+
GammaDistribution = Rubystats::GammaDistribution
|
31
|
+
MultivariateNormalDistribution = Rubystats::MultivariateNormalDistribution
|
32
|
+
|
33
|
+
#short-hand notation
|
34
|
+
Normal = Rubystats::NormalDistribution
|
35
|
+
Binomial = Rubystats::BinomialDistribution
|
36
|
+
Poisson = Rubystats::PoissonDistribution
|
37
|
+
Beta = Rubystats::BetaDistribution
|
38
|
+
Exponential = Rubystats::ExponentialDistribution
|
39
|
+
Uniform = Rubystats::UniformDistribution
|
40
|
+
Lognormal = Rubystats::LognormalDistribution
|
41
|
+
Weibull = Rubystats::WeibullDistribution
|
42
|
+
Cauchy = Rubystats::CauchyDistribution
|
43
|
+
Gamma = Rubystats::GammaDistribution
|
44
|
+
MultivariateNormal = Rubystats::MultivariateNormalDistribution
|
@@ -9,6 +9,7 @@ module Rubystats
|
|
9
9
|
include Rubystats::NumericalConstants
|
10
10
|
include Rubystats::SpecialMath
|
11
11
|
include Rubystats::ExtraMath
|
12
|
+
include Rubystats::MakeDiscrete
|
12
13
|
|
13
14
|
attr_reader :p, :n
|
14
15
|
attr_writer :p, :n
|
@@ -18,11 +19,11 @@ module Rubystats
|
|
18
19
|
if trials <= 0
|
19
20
|
raise ArgumentError.new("Error: trials must be greater than 0")
|
20
21
|
end
|
21
|
-
@n = trials
|
22
|
+
@n = trials.to_i
|
22
23
|
if prob < 0.0 || prob > 1.0
|
23
24
|
raise ArgumentError.new("prob must be between 0 and 1")
|
24
25
|
end
|
25
|
-
@p = prob
|
26
|
+
@p = prob.to_f
|
26
27
|
end
|
27
28
|
|
28
29
|
#returns the number of trials
|
@@ -45,79 +46,20 @@ module Rubystats
|
|
45
46
|
@n * @p * (1.0 - @p)
|
46
47
|
end
|
47
48
|
|
49
|
+
# Private methods below
|
50
|
+
|
51
|
+
private
|
52
|
+
|
48
53
|
# Probability density function of a binomial distribution (equivalent
|
49
54
|
# to R dbinom function).
|
50
55
|
# _x should be an integer
|
51
56
|
# returns the probability that a stochastic variable x has the value _x,
|
52
57
|
# i.e. P(x = _x)
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
for i in (0 ... _x.length)
|
57
|
-
check_range(_x[i], 0.0, @n)
|
58
|
-
pdf_vals[i] = binomial(@n, _x[i]) * (1-@p)**(@n-_x[i])
|
59
|
-
end
|
60
|
-
return pdf_vals
|
61
|
-
else
|
62
|
-
check_range(_x, 0.0, @n)
|
63
|
-
return binomial(@n, _x) * @p**_x * (1-@p)**(@n-_x)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
# Cumulative binomial distribution function (equivalent to R pbinom function).
|
68
|
-
# _x should be integer-valued and can be single integer or array of integers
|
69
|
-
# returns single value or array containing probability that a stochastic
|
70
|
-
# variable x is less then X, i.e. P(x < _x).
|
71
|
-
def cdf(_x)
|
72
|
-
if _x.class == Array
|
73
|
-
pdf_vals = []
|
74
|
-
for i in (0 ..._x.length)
|
75
|
-
pdf_vals[i] = get_cdf(_x[i])
|
76
|
-
end
|
77
|
-
return pdf_vals
|
78
|
-
else
|
79
|
-
return get_cdf(_x)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# Inverse of the cumulative binomial distribution function
|
84
|
-
# (equivalent to R qbinom function).
|
85
|
-
# returns the value X for which P(x < _x).
|
86
|
-
def get_icdf(prob)
|
87
|
-
if prob.class == Array
|
88
|
-
inv_vals = []
|
89
|
-
for i in (0 ...prob.length)
|
90
|
-
check_range(prob[i])
|
91
|
-
inv_vals[i] = (find_root(prob[i], @n/2, 0.0, @n)).floor
|
92
|
-
end
|
93
|
-
return inv_vals
|
94
|
-
else
|
95
|
-
check_range(prob)
|
96
|
-
return (find_root(prob, @n/2, 0.0, @n)).floor
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
# Wrapper for binomial RNG function (equivalent to R rbinom function).
|
101
|
-
# returns random deviate given trials and p
|
102
|
-
def rng(num_vals = 1)
|
103
|
-
if num_vals < 1
|
104
|
-
raise "Error num_vals must be greater than or equal to 1"
|
105
|
-
end
|
106
|
-
if num_vals == 1
|
107
|
-
return get_rng
|
108
|
-
else
|
109
|
-
rand_vals = []
|
110
|
-
for i in (0 ...num_vals)
|
111
|
-
rand_vals[i] = get_rng
|
112
|
-
end
|
113
|
-
return rand_vals
|
114
|
-
end
|
58
|
+
def get_pdf(x)
|
59
|
+
check_range(x, 0, @n)
|
60
|
+
binomial(@n, x) * @p**x * (1-@p)**(@n-x)
|
115
61
|
end
|
116
62
|
|
117
|
-
# Private methods below
|
118
|
-
|
119
|
-
private
|
120
|
-
|
121
63
|
# Private shared function for getting cumulant for particular x
|
122
64
|
# param _x should be integer-valued
|
123
65
|
# returns the probability that a stochastic variable x is less than _x
|
@@ -128,71 +70,40 @@ module Rubystats
|
|
128
70
|
for i in (0 .. _x)
|
129
71
|
sum = sum + pdf(i)
|
130
72
|
end
|
131
|
-
|
73
|
+
sum
|
132
74
|
end
|
133
75
|
|
134
|
-
#
|
135
|
-
#
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
# port conforms to the Press et al. copyright.
|
146
|
-
def get_rng
|
147
|
-
nold = -1
|
148
|
-
pold = -1
|
149
|
-
p = (if @p <= 0.5 then @p else 1.0 - @p end)
|
150
|
-
am = @n * p
|
151
|
-
if @n < 25
|
152
|
-
bnl = 0.0
|
153
|
-
(1...@n).each do
|
154
|
-
if Kernel.rand < p
|
155
|
-
bnl = bnl.next
|
156
|
-
end
|
157
|
-
end
|
158
|
-
elsif am < 1.0
|
159
|
-
g = Math.exp(-am)
|
160
|
-
t = 1.0
|
161
|
-
for j in (0 ... @n)
|
162
|
-
t = t * Kernel.rand
|
163
|
-
break if t < g
|
164
|
-
end
|
165
|
-
bnl = (if j <= @n then j else @n end)
|
166
|
-
else
|
167
|
-
if n != nold
|
168
|
-
en = @n
|
169
|
-
oldg = log_gamma(en + 1.0)
|
170
|
-
nold = n
|
171
|
-
end
|
172
|
-
if p != pold
|
173
|
-
pc = 1.0 - p
|
174
|
-
plog = Math.log(p)
|
175
|
-
pclog = Math.log(pc)
|
176
|
-
pold = p
|
177
|
-
end
|
178
|
-
sq = Math.sqrt(2.0 * am * pc)
|
179
|
-
until Kernel.rand <= t do
|
180
|
-
until (em >= 0.0 || em < (en + 1.0)) do
|
181
|
-
angle = Pi * Kernel.rand
|
182
|
-
y = Math.tan(angle)
|
183
|
-
em = sq * y + am
|
184
|
-
end
|
185
|
-
em = em.floor
|
186
|
-
t = 1.2 * sq * (1.0 + y * y) *
|
187
|
-
Math.exp(oldg - log_gamma(em + 1.0) -
|
188
|
-
log_gamma(en - em + 1.0) + em * plog + (en - em) * pclog)
|
189
|
-
end
|
190
|
-
bnl = em
|
191
|
-
end
|
192
|
-
if p != @p
|
193
|
-
bnl = @n - bnl
|
194
|
-
end
|
195
|
-
return bnl
|
76
|
+
# Inverse of the cumulative binomial distribution function
|
77
|
+
# returns the value X for which P(x < _x).
|
78
|
+
def get_icdf(prob)
|
79
|
+
check_range(prob)
|
80
|
+
sum = 0.0
|
81
|
+
k = 0
|
82
|
+
until prob <= sum
|
83
|
+
sum += get_pdf(k)
|
84
|
+
k += 1
|
85
|
+
end
|
86
|
+
k - 1
|
196
87
|
end
|
88
|
+
|
89
|
+
# Private binomial RNG function
|
90
|
+
# Variation of Luc Devroye's "Second Waiting Time Method"
|
91
|
+
# on page 522 of his text "Non-Uniform Random Variate Generation."
|
92
|
+
# There are faster methods based on acceptance/rejection techniques,
|
93
|
+
# but they are substantially more complex to implement.
|
94
|
+
def get_rng
|
95
|
+
p = (@p <= 0.5) ? @p : (1.0 - @p)
|
96
|
+
log_q = Math.log(1.0 - p)
|
97
|
+
sum = 0.0
|
98
|
+
k = 0
|
99
|
+
loop do
|
100
|
+
sum += Math.log(Kernel.rand) / (@n - k)
|
101
|
+
if (sum < log_q)
|
102
|
+
return (p != @p) ? (@n - k) : k
|
103
|
+
end
|
104
|
+
k += 1
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
197
108
|
end
|
198
109
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubystats/probability_distribution'
|
2
|
+
module Rubystats
|
3
|
+
class CauchyDistribution < Rubystats::ProbabilityDistribution
|
4
|
+
|
5
|
+
def initialize(location=1.0,scale=1.0)
|
6
|
+
if scale <= 0.0
|
7
|
+
raise ArgumentError.new("Scale parameter in Cauchy distribution should be greater than zero.")
|
8
|
+
end
|
9
|
+
@location = location.to_f
|
10
|
+
@scale = scale.to_f
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def get_mean
|
16
|
+
Float::NAN
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_variance
|
20
|
+
Float::NAN
|
21
|
+
end
|
22
|
+
|
23
|
+
# Private method to obtain single PDF value.
|
24
|
+
# x should be greater than 0
|
25
|
+
# returns the probability that a stochastic variable x has the value X, i.e. P(x=X).
|
26
|
+
def get_pdf(x)
|
27
|
+
1.0 / (Math::PI * @scale * (1.0 + ((x - @location) / @scale)**2))
|
28
|
+
end
|
29
|
+
|
30
|
+
# Private method to obtain single CDF value.
|
31
|
+
# param x should be greater than 0
|
32
|
+
# return the probability that a stochastic variable x is less then X, i.e. P(x<X).
|
33
|
+
def get_cdf(x)
|
34
|
+
(1.0 / Math::PI) * Math.atan((x - @location) / @scale) + 0.5
|
35
|
+
end
|
36
|
+
|
37
|
+
# Private method to obtain single inverse CDF value.
|
38
|
+
# return the value X for which P(x<X).
|
39
|
+
def get_icdf(p)
|
40
|
+
check_range(p)
|
41
|
+
@location + @scale * Math.tan(Math::PI * (p - 0.5))
|
42
|
+
end
|
43
|
+
|
44
|
+
# Private method to obtain single RNG value.
|
45
|
+
def get_rng
|
46
|
+
self.icdf(Kernel.rand)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -10,11 +10,11 @@ module Rubystats
|
|
10
10
|
include Rubystats::SpecialMath
|
11
11
|
include Rubystats::ExtraMath
|
12
12
|
|
13
|
-
def initialize(decay=1)
|
13
|
+
def initialize(decay=1.0)
|
14
14
|
if decay < 0.0
|
15
15
|
raise ArgumentError.new("Decay parameter should be positive.")
|
16
16
|
end
|
17
|
-
@rate = decay
|
17
|
+
@rate = decay.to_f
|
18
18
|
end
|
19
19
|
|
20
20
|
private
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rubystats/normal_distribution'
|
2
|
+
require 'rubystats/probability_distribution'
|
3
|
+
module Rubystats
|
4
|
+
class GammaDistribution < Rubystats::ProbabilityDistribution
|
5
|
+
include Rubystats::NumericalConstants
|
6
|
+
include Rubystats::SpecialMath
|
7
|
+
|
8
|
+
def initialize(shape=1.0, scale=1.0)
|
9
|
+
if shape <= 0.0 || scale <= 0.0
|
10
|
+
raise ArgumentError.new("Input parameter should be greater than zero.")
|
11
|
+
end
|
12
|
+
@shape = shape.to_f
|
13
|
+
@scale = scale.to_f
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def get_mean
|
19
|
+
@scale * @shape
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_variance
|
23
|
+
@shape * (@scale)**2
|
24
|
+
end
|
25
|
+
|
26
|
+
# Private method to obtain single PDF value.
|
27
|
+
# x should be greater than or equal to 0.0
|
28
|
+
# returns the probability that a stochastic variable x has the value X, i.e. P(x=X).
|
29
|
+
def get_pdf(x)
|
30
|
+
check_range(x, 0.0, MAX_VALUE)
|
31
|
+
1.0 / (Math.gamma(@shape) * (@scale**@shape)) * (x**(@shape-1.0)) * Math.exp(-1.0 * x / @scale)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Private method to obtain single CDF value.
|
35
|
+
# param x should be greater than 0
|
36
|
+
# return the probability that a stochastic variable x is less then X, i.e. P(x<X).
|
37
|
+
def get_cdf(x)
|
38
|
+
check_range(x,0.0,MAX_VALUE)
|
39
|
+
@scale * incomplete_gamma(@shape, x/@scale) / Math.gamma(@shape)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Private method to obtain single inverse CDF value.
|
43
|
+
# return the value X for which P(x<X).
|
44
|
+
def get_icdf(p)
|
45
|
+
check_range(p)
|
46
|
+
raise "Inverse CDF for gamma not implemented yet."
|
47
|
+
end
|
48
|
+
|
49
|
+
# Private method to obtain single RNG value.
|
50
|
+
# Generate gamma random variate with
|
51
|
+
# Marsaglia's squeeze method.
|
52
|
+
def get_rng
|
53
|
+
raise "Gamma RNG not working for shape < 1" if @shape < 1.0
|
54
|
+
norm = Rubystats::NormalDistribution.new(0,1)
|
55
|
+
d = @shape - 1.0 / 3.0
|
56
|
+
c = 1.0 / Math.sqrt(9.0 * d)
|
57
|
+
MAX_ITERATIONS.times do
|
58
|
+
x = norm.rng
|
59
|
+
v = (1.0 + c * x)**(3.0)
|
60
|
+
next if v <= 0.0
|
61
|
+
u = Kernel.rand
|
62
|
+
if (u < 1.0 - 0.03331 * (x**4)) || (Math.log(u) < 0.5 * x**2 + d * (1.0 - v + Math.log(v)))
|
63
|
+
return (d * v) * @scale
|
64
|
+
end
|
65
|
+
end
|
66
|
+
raise "Gamma RNG not converged after max_iterations = #{MAX_ITERATIONS}"
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|