rubystats 0.2.1 → 0.2.2
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 +5 -1
- data/Manifest.txt +3 -0
- data/README.txt +6 -2
- data/Rakefile +23 -0
- data/examples/exponential.rb +5 -0
- data/lib/rubystats.rb +2 -1
- data/lib/rubystats/binomial_distribution.rb +10 -7
- data/lib/rubystats/exponential_distribution.rb +60 -0
- data/lib/rubystats/modules.rb +67 -67
- data/lib/rubystats/normal_distribution.rb +6 -6
- data/lib/rubystats/probability_distribution.rb +56 -16
- data/test/tc_beta.rb +8 -3
- data/test/tc_exponential.rb +60 -0
- data/test/tc_require_all.rb +2 -0
- data/test/ts_stats.rb +2 -0
- metadata +5 -2
data/History.txt
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
=== 0.2.2 / 2008-05-09
|
2
|
+
* Added exponential distribution class
|
3
|
+
* Replaced constants in NumericalConstants module with uppercase versions to follow Ruby convention
|
4
|
+
|
1
5
|
=== 0.2.1 / 2008-05-08
|
2
6
|
* Bug fix for Normal Distribution RNG function (RubyForge bug #20044)
|
3
7
|
* thanks, Daniel Moore (yahivin)
|
@@ -8,4 +12,4 @@
|
|
8
12
|
* Added lib/rubystats subdirectory and namespaced all classes under the Rubystats module.
|
9
13
|
* Added another example or two and fixed bug #16827.
|
10
14
|
* Should not break old API
|
11
|
-
*Now using Hoe to manage gem.
|
15
|
+
* Now using Hoe to manage gem.
|
data/Manifest.txt
CHANGED
@@ -4,18 +4,21 @@ README.txt
|
|
4
4
|
Rakefile
|
5
5
|
examples/beta.rb
|
6
6
|
examples/binomial.rb
|
7
|
+
examples/exponential.rb
|
7
8
|
examples/failrate_vs_goal.rb
|
8
9
|
examples/fisher.rb
|
9
10
|
examples/norm.rb
|
10
11
|
lib/rubystats.rb
|
11
12
|
lib/rubystats/beta_distribution.rb
|
12
13
|
lib/rubystats/binomial_distribution.rb
|
14
|
+
lib/rubystats/exponential_distribution.rb
|
13
15
|
lib/rubystats/fishers_exact_test.rb
|
14
16
|
lib/rubystats/modules.rb
|
15
17
|
lib/rubystats/normal_distribution.rb
|
16
18
|
lib/rubystats/probability_distribution.rb
|
17
19
|
test/tc_beta.rb
|
18
20
|
test/tc_binomial.rb
|
21
|
+
test/tc_exponential.rb
|
19
22
|
test/tc_fisher.rb
|
20
23
|
test/tc_norm.rb
|
21
24
|
test/tc_require_all.rb
|
data/README.txt
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
=
|
1
|
+
= Rubystats
|
2
2
|
|
3
3
|
* http://rubyforge.org/projects/rubystats/
|
4
4
|
|
@@ -9,6 +9,9 @@
|
|
9
9
|
various sources).
|
10
10
|
See http://www.phpmath.com/ for PHPMath libraries.
|
11
11
|
|
12
|
+
Currently includes classes for normal, binomial, beta and exponential distributions, with more
|
13
|
+
planned to be added.
|
14
|
+
|
12
15
|
See examples and tests for usage.
|
13
16
|
|
14
17
|
== NOTE for version 0.2.0:
|
@@ -30,7 +33,7 @@
|
|
30
33
|
2006-2008
|
31
34
|
|
32
35
|
|
33
|
-
== WARNING
|
36
|
+
== WARNING:
|
34
37
|
This is beta-quality software. It works well according to my tests, but the API may change and other features may be added.
|
35
38
|
|
36
39
|
== FEATURES:
|
@@ -39,6 +42,7 @@ Classes for distributions:
|
|
39
42
|
* Normal
|
40
43
|
* Binomial
|
41
44
|
* Beta
|
45
|
+
* Exponential
|
42
46
|
|
43
47
|
Also includes Fisher's Exact Test
|
44
48
|
|
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
4
|
require 'hoe'
|
3
5
|
$:.unshift(File.dirname(__FILE__) + "/lib")
|
@@ -17,3 +19,24 @@ end
|
|
17
19
|
rule '' do |t|
|
18
20
|
system "cd test && ruby ts_stats.rb"
|
19
21
|
end
|
22
|
+
|
23
|
+
ALLISON = "/opt/local/lib/ruby/gems/1.8/gems/allison-2.0.3/lib/allison.rb"
|
24
|
+
|
25
|
+
Rake::RDocTask.new do |rd|
|
26
|
+
rd.main = "README.txt"
|
27
|
+
rd.rdoc_dir = "doc"
|
28
|
+
rd.rdoc_files.include(
|
29
|
+
"README.txt",
|
30
|
+
"History.txt",
|
31
|
+
"Manifest.txt",
|
32
|
+
"lib/**/*.rb",
|
33
|
+
"examples/**/*.rb",
|
34
|
+
"test/**/*.rb")
|
35
|
+
rd.title = "Rubystats RDoc"
|
36
|
+
|
37
|
+
rd.options << '-S' # inline source
|
38
|
+
|
39
|
+
rd.template = ALLISON if File.exist?(ALLISON)
|
40
|
+
end
|
41
|
+
|
42
|
+
# vim: syntax=Ruby
|
data/lib/rubystats.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
module Rubystats
|
2
|
-
VERSION = '0.2.
|
2
|
+
VERSION = '0.2.2'
|
3
3
|
end
|
4
4
|
|
5
5
|
require 'rubystats/normal_distribution'
|
6
6
|
require 'rubystats/binomial_distribution'
|
7
7
|
require 'rubystats/beta_distribution'
|
8
8
|
require 'rubystats/fishers_exact_test'
|
9
|
+
require 'rubystats/exponential_distribution'
|
9
10
|
include Rubystats
|
@@ -10,36 +10,39 @@ module Rubystats
|
|
10
10
|
include Rubystats::SpecialMath
|
11
11
|
include Rubystats::ExtraMath
|
12
12
|
|
13
|
+
attr_reader :p, :n
|
14
|
+
attr_writer :p, :n
|
15
|
+
|
13
16
|
# Constructs a binomial distribution
|
14
17
|
def initialize (trials, prob)
|
15
18
|
if trials <= 0
|
16
|
-
raise "Error: trials must be greater than 0"
|
19
|
+
raise ArgumentError.new("Error: trials must be greater than 0")
|
17
20
|
end
|
18
21
|
@n = trials
|
19
22
|
if prob < 0.0 || prob > 1.0
|
20
|
-
raise "
|
23
|
+
raise ArgumentError.new("prob must be between 0 and 1")
|
21
24
|
end
|
22
25
|
@p = prob
|
23
26
|
end
|
24
27
|
|
25
28
|
#returns the number of trials
|
26
29
|
def get_trials_parameter
|
27
|
-
|
30
|
+
@n
|
28
31
|
end
|
29
32
|
|
30
33
|
#returns the probability
|
31
34
|
def get_probability_parameter
|
32
|
-
|
35
|
+
@p
|
33
36
|
end
|
34
37
|
|
35
38
|
#returns the mean
|
36
39
|
def get_mean
|
37
|
-
|
40
|
+
@n * @p
|
38
41
|
end
|
39
42
|
|
40
43
|
#returns the variance
|
41
|
-
def
|
42
|
-
|
44
|
+
def get_variance
|
45
|
+
@n * @p * (1.0 - @p)
|
43
46
|
end
|
44
47
|
|
45
48
|
# Probability density function of a binomial distribution (equivalent
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubystats/probability_distribution'
|
2
|
+
# This class provides an object for encapsulating exponential distributions
|
3
|
+
# Ported to Ruby from PHPMath class by Bryan Donovan
|
4
|
+
# Author:: Mark Hale
|
5
|
+
# Author:: Paul Meagher
|
6
|
+
# Author:: Bryan Donovan (http://www.bryandonovan.com)
|
7
|
+
module Rubystats
|
8
|
+
class ExponentialDistribution < Rubystats::ProbabilityDistribution
|
9
|
+
include Rubystats::NumericalConstants
|
10
|
+
include Rubystats::SpecialMath
|
11
|
+
include Rubystats::ExtraMath
|
12
|
+
|
13
|
+
def initialize(decay=1)
|
14
|
+
if decay < 0.0
|
15
|
+
raise ArgumentError.new("Decay parameter should be positive.")
|
16
|
+
end
|
17
|
+
@rate = decay
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def get_mean
|
23
|
+
@rate
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_variance
|
27
|
+
@rate * @rate
|
28
|
+
end
|
29
|
+
|
30
|
+
# Private method to obtain single PDF value.
|
31
|
+
# x should be greater than 0
|
32
|
+
# returns the probability that a stochastic variable x has the value X, i.e. P(x=X).
|
33
|
+
def get_pdf(x)
|
34
|
+
check_range(x, 0.0, MAX_VALUE)
|
35
|
+
@rate * Math.exp(-1 * @rate * x)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Private method to obtain single CDF value.
|
39
|
+
# param x should be greater than 0
|
40
|
+
# return the probability that a stochastic variable x is less then X, i.e. P(x<X).
|
41
|
+
def get_cdf(x)
|
42
|
+
check_range(x,0.0,MAX_VALUE)
|
43
|
+
1.0 - Math.exp(-1 * @rate * x)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Private method to obtain single inverse CDF value.
|
47
|
+
# return the value X for which P(x<X).
|
48
|
+
def get_icdf(p)
|
49
|
+
check_range(p)
|
50
|
+
-1 * Math.log(1.0 - p) / @rate
|
51
|
+
end
|
52
|
+
|
53
|
+
# Private method to obtain single RNG value.
|
54
|
+
# return exponential random deviate
|
55
|
+
def get_rng
|
56
|
+
-(Math.log(Kernel.rand) / @rate)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
data/lib/rubystats/modules.rb
CHANGED
@@ -7,19 +7,19 @@ module Rubystats
|
|
7
7
|
end
|
8
8
|
|
9
9
|
module NumericalConstants
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
10
|
+
MAX_FLOAT = 3.40282346638528860e292
|
11
|
+
EPS = 2.22e-16
|
12
|
+
MAX_VALUE = 1.2e290
|
13
|
+
LOG_GAMMA_X_MAX_VALUE = 2.55e292
|
14
|
+
GAMMA_X_MAX_VALUE = 171.624
|
15
|
+
SQRT2PI = 2.5066282746310005024157652848110452530069867406099
|
16
|
+
SQRT2 = 1.4142135623730950488016887242096980785696718753769
|
17
|
+
XMININ = 2.23e-303
|
18
|
+
MAX_ITERATIONS = 1000
|
19
|
+
PRECISION = 8.88e-016
|
20
|
+
TWO_PI = 6.2831853071795864769252867665590057683943387987502
|
21
|
+
GAMMA = 0.57721566490153286060651209008240243104215933593992
|
22
|
+
GOLDEN_RATIO = 1.6180339887498948482045868343656381177203091798058
|
23
23
|
end
|
24
24
|
|
25
25
|
|
@@ -36,8 +36,8 @@ module Rubystats
|
|
36
36
|
|
37
37
|
include Rubystats::NumericalConstants
|
38
38
|
|
39
|
-
@
|
40
|
-
@
|
39
|
+
@logGAMMACache_res = 0.0
|
40
|
+
@logGAMMACache_x = 0.0
|
41
41
|
@logBetaCache_res = 0.0
|
42
42
|
@logBetaCache_p = 0.0
|
43
43
|
@logBetaCache_q = 0.0
|
@@ -46,7 +46,7 @@ module Rubystats
|
|
46
46
|
if p != @logBetaCache_p || q != @logBetaCache_q
|
47
47
|
logBetaCache_p = p
|
48
48
|
logBetaCache_q = q
|
49
|
-
if p <= 0.0 || q <= 0.0 || (p + q) >
|
49
|
+
if p <= 0.0 || q <= 0.0 || (p + q) > LOG_GAMMA_X_MAX_VALUE
|
50
50
|
logBetaCache_res = 0.0
|
51
51
|
else
|
52
52
|
logBetaCache_res = log_gamma(p) + log_gamma(q) - log_gamma(p + q)
|
@@ -55,7 +55,7 @@ module Rubystats
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
#
|
58
|
+
# GAMMA function.
|
59
59
|
# Based on public domain NETLIB (Fortran) code by W. J. Cody and L. Stoltz<BR>
|
60
60
|
# Applied Mathematics Division<BR>
|
61
61
|
# Argonne National Laboratory<BR>
|
@@ -84,8 +84,8 @@ module Rubystats
|
|
84
84
|
# </P>
|
85
85
|
# Author:: Jaco van Kooten
|
86
86
|
|
87
|
-
def
|
88
|
-
#
|
87
|
+
def GAMMA(x)
|
88
|
+
# GAMMA related constants
|
89
89
|
g_p = [ -1.71618513886549492533811, 24.7656508055759199108314,
|
90
90
|
-379.804256470945635097577, 629.331155312818442661052,
|
91
91
|
866.966202790413211295064, -31451.2729688483675254357,
|
@@ -116,21 +116,21 @@ module Rubystats
|
|
116
116
|
y += 1
|
117
117
|
end
|
118
118
|
else
|
119
|
-
return
|
119
|
+
return MAX_VALUE
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
123
|
# ----------------------------------------------------------------------
|
124
124
|
# Argument is positive
|
125
125
|
# ----------------------------------------------------------------------
|
126
|
-
if y <
|
126
|
+
if y < EPS
|
127
127
|
# ----------------------------------------------------------------------
|
128
128
|
# Argument .LT. EPS
|
129
129
|
# ----------------------------------------------------------------------
|
130
|
-
if y >=
|
130
|
+
if y >= XMININ
|
131
131
|
res = 1.0 / y
|
132
132
|
else
|
133
|
-
return
|
133
|
+
return MAX_VALUE
|
134
134
|
end
|
135
135
|
elsif y < 12.0
|
136
136
|
y1 = y
|
@@ -177,17 +177,17 @@ module Rubystats
|
|
177
177
|
# ----------------------------------------------------------------------
|
178
178
|
# Evaluate for argument .GE. 12.0
|
179
179
|
# ----------------------------------------------------------------------
|
180
|
-
if y <=
|
180
|
+
if y <= GAMMA_X_MAX_VALUE
|
181
181
|
ysq = y * y
|
182
182
|
sum = g_c[6]
|
183
183
|
for i in(0...6)
|
184
184
|
sum = sum / ysq + g_c[i]
|
185
|
-
sum = sum / y - y + log(
|
185
|
+
sum = sum / y - y + log(SQRT2PI)
|
186
186
|
sum += (y - 0.5) * log(y)
|
187
187
|
res = Math.exp(sum)
|
188
188
|
end
|
189
189
|
else
|
190
|
-
return
|
190
|
+
return MAX_VALUE
|
191
191
|
end
|
192
192
|
# ----------------------------------------------------------------------
|
193
193
|
# Final adjustments and return
|
@@ -203,8 +203,8 @@ module Rubystats
|
|
203
203
|
end
|
204
204
|
|
205
205
|
def log_gamma(x)
|
206
|
-
|
207
|
-
|
206
|
+
logGAMMACache_res = @logGAMMACache_res
|
207
|
+
logGAMMACache_x = @logGAMMACache_x
|
208
208
|
|
209
209
|
lg_d1 = -0.5772156649015328605195174
|
210
210
|
lg_d2 = 0.4227843350984671393993777
|
@@ -251,17 +251,17 @@ module Rubystats
|
|
251
251
|
-0.002777777777777681622553, 0.08333333333333333331554247,
|
252
252
|
0.0057083835261 ]
|
253
253
|
|
254
|
-
# Rough estimate of the fourth root of
|
254
|
+
# Rough estimate of the fourth root of logGAMMA_xBig
|
255
255
|
lg_frtbig = 2.25e76
|
256
256
|
pnt68 = 0.6796875
|
257
257
|
|
258
|
-
if x ==
|
259
|
-
return
|
258
|
+
if x == logGAMMACache_x
|
259
|
+
return logGAMMACache_res
|
260
260
|
end
|
261
261
|
|
262
262
|
y = x
|
263
|
-
if y > 0.0 && y <=
|
264
|
-
if y <=
|
263
|
+
if y > 0.0 && y <= LOG_GAMMA_X_MAX_VALUE
|
264
|
+
if y <= EPS
|
265
265
|
res = -Math.log(y)
|
266
266
|
elsif y <= 1.5
|
267
267
|
# EPS .LT. X .LE. 1.5
|
@@ -323,21 +323,21 @@ module Rubystats
|
|
323
323
|
end
|
324
324
|
res = res/y
|
325
325
|
corr = Math.log(y)
|
326
|
-
res = res + Math.log(
|
326
|
+
res = res + Math.log(SQRT2PI) - 0.5 * corr
|
327
327
|
res = res + y * (corr - 1.0)
|
328
328
|
end
|
329
329
|
else
|
330
330
|
#return for bad arguments
|
331
|
-
res =
|
331
|
+
res = MAX_VALUE
|
332
332
|
end
|
333
333
|
# final adjustments and return
|
334
|
-
|
335
|
-
|
334
|
+
logGAMMACache_x = x
|
335
|
+
logGAMMACache_res = res
|
336
336
|
return res
|
337
337
|
end
|
338
338
|
|
339
339
|
|
340
|
-
# Incomplete
|
340
|
+
# Incomplete GAMMA function.
|
341
341
|
# The computation is based on approximations presented in
|
342
342
|
# Numerical Recipes, Chapter 6.2 (W.H. Press et al, 1992).
|
343
343
|
# @param a require a>=0
|
@@ -345,26 +345,26 @@ module Rubystats
|
|
345
345
|
# @return 0 if x<0, a<=0 or a>2.55E305 to avoid errors and over/underflow
|
346
346
|
# @author Jaco van Kooten
|
347
347
|
|
348
|
-
def
|
349
|
-
if x <= 0.0 || a <= 0.0 || a >
|
348
|
+
def incomplete_GAMMA(a, x)
|
349
|
+
if x <= 0.0 || a <= 0.0 || a > LOG_GAMMA_X_MAX_VALUE
|
350
350
|
return 0.0
|
351
351
|
elsif x < (a + 1.0)
|
352
|
-
return
|
352
|
+
return GAMMA_series_expansion(a, x)
|
353
353
|
else
|
354
|
-
return 1.0-
|
354
|
+
return 1.0-GAMMA_fraction(a, x)
|
355
355
|
end
|
356
356
|
end
|
357
357
|
|
358
358
|
# Author:: Jaco van Kooten
|
359
|
-
def
|
359
|
+
def GAMMA_series_expansion(a, x)
|
360
360
|
ap = a
|
361
361
|
del = 1.0 / a
|
362
362
|
sum = del
|
363
|
-
for n in (1...
|
363
|
+
for n in (1...MAX_ITERATIONS)
|
364
364
|
ap += 1
|
365
365
|
del *= x / ap
|
366
366
|
sum += del
|
367
|
-
if del < sum *
|
367
|
+
if del < sum * PRECISION
|
368
368
|
return sum * Math.exp(-x + a * Math.log(x) - log_gamma(a))
|
369
369
|
end
|
370
370
|
end
|
@@ -372,23 +372,23 @@ module Rubystats
|
|
372
372
|
end
|
373
373
|
|
374
374
|
# Author:: Jaco van Kooten
|
375
|
-
def
|
375
|
+
def GAMMA_fraction(a, x)
|
376
376
|
b = x + 1.0 - a
|
377
|
-
c = 1.0 /
|
377
|
+
c = 1.0 / XMININ
|
378
378
|
d = 1.0 / b
|
379
379
|
h = d
|
380
380
|
del= 0.0
|
381
381
|
an = 0.0
|
382
|
-
for i in (1...
|
383
|
-
if (del-1.0).abs >
|
382
|
+
for i in (1...MAX_ITERATIONS)
|
383
|
+
if (del-1.0).abs > PRECISION
|
384
384
|
an = -i * (i - a)
|
385
385
|
b += 2.0
|
386
386
|
d = an * d + b
|
387
387
|
c = b + an / c
|
388
|
-
if c.abs <
|
389
|
-
c =
|
390
|
-
if d.abs <
|
391
|
-
c =
|
388
|
+
if c.abs < XMININ
|
389
|
+
c = XMININ
|
390
|
+
if d.abs < XMININ
|
391
|
+
c = XMININ
|
392
392
|
d = 1.0 / d
|
393
393
|
del = d * c
|
394
394
|
h *= del
|
@@ -404,7 +404,7 @@ module Rubystats
|
|
404
404
|
# Author:: Jaco van Kooten
|
405
405
|
|
406
406
|
def beta(p, q)
|
407
|
-
if p <= 0.0 || q <= 0.0 || (p + q) >
|
407
|
+
if p <= 0.0 || q <= 0.0 || (p + q) > LOG_GAMMA_X_MAX_VALUE
|
408
408
|
return 0.0
|
409
409
|
else
|
410
410
|
return Math.exp(log_beta(p, q))
|
@@ -424,7 +424,7 @@ module Rubystats
|
|
424
424
|
return 0.0
|
425
425
|
elsif x >= 1.0
|
426
426
|
return 1.0
|
427
|
-
elsif p <= 0.0 || q <= 0.0 || (p + q) >
|
427
|
+
elsif p <= 0.0 || q <= 0.0 || (p + q) > LOG_GAMMA_X_MAX_VALUE
|
428
428
|
return 0.0
|
429
429
|
else
|
430
430
|
beta_gam = Math.exp( -log_beta(p, q) + p * Math.log(x) + q * Math.log(1.0 - x) )
|
@@ -448,38 +448,38 @@ module Rubystats
|
|
448
448
|
p_plus = p + 1.0
|
449
449
|
p_minus = p - 1.0
|
450
450
|
h = 1.0 - sum_pq * x / p_plus
|
451
|
-
if h.abs <
|
452
|
-
h =
|
451
|
+
if h.abs < XMININ
|
452
|
+
h = XMININ
|
453
453
|
end
|
454
454
|
h = 1.0 / h
|
455
455
|
frac = h
|
456
456
|
m = 1
|
457
457
|
delta = 0.0
|
458
458
|
|
459
|
-
while (m <=
|
459
|
+
while (m <= MAX_ITERATIONS) && ((delta - 1.0).abs > PRECISION)
|
460
460
|
m2 = 2 * m
|
461
461
|
# even index for d
|
462
462
|
d = m * (q - m) * x / ( (p_minus + m2) * (p + m2))
|
463
463
|
h = 1.0 + d * h
|
464
|
-
if h.abs <
|
465
|
-
h =
|
464
|
+
if h.abs < XMININ
|
465
|
+
h = XMININ
|
466
466
|
end
|
467
467
|
h = 1.0 / h
|
468
468
|
c = 1.0 + d / c
|
469
|
-
if c.abs <
|
470
|
-
c =
|
469
|
+
if c.abs < XMININ
|
470
|
+
c = XMININ
|
471
471
|
end
|
472
472
|
frac *= h * c
|
473
473
|
# odd index for d
|
474
474
|
d = -(p + m) * (sum_pq + m) * x / ((p + m2) * (p_plus + m2))
|
475
475
|
h = 1.0 + d * h
|
476
|
-
if h.abs <
|
477
|
-
h =
|
476
|
+
if h.abs < XMININ
|
477
|
+
h = XMININ
|
478
478
|
end
|
479
479
|
h = 1.0 / h
|
480
480
|
c = 1.0 + d / c
|
481
|
-
if c.abs <
|
482
|
-
c =
|
481
|
+
if c.abs < XMININ
|
482
|
+
c = XMININ
|
483
483
|
end
|
484
484
|
delta = h * c
|
485
485
|
frac *= delta
|
@@ -563,7 +563,7 @@ module Rubystats
|
|
563
563
|
#
|
564
564
|
# Note1:
|
565
565
|
# To compute exp(-x*x-0.5625+R/S), let s be a single
|
566
|
-
#
|
566
|
+
# PRECISION number and s := x then
|
567
567
|
# -x*x = -s*s + (s-x)*(s+x)
|
568
568
|
# exp(-x*x-0.5626+R/S) =
|
569
569
|
# exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S)
|
@@ -17,8 +17,8 @@ module Rubystats
|
|
17
17
|
end
|
18
18
|
@stdev = sigma
|
19
19
|
@variance = sigma**2
|
20
|
-
@pdf_denominator =
|
21
|
-
@cdf_denominator =
|
20
|
+
@pdf_denominator = SQRT2PI * Math.sqrt(@variance)
|
21
|
+
@cdf_denominator = SQRT2 * Math.sqrt(@variance)
|
22
22
|
end
|
23
23
|
|
24
24
|
# Returns the mean of the distribution
|
@@ -57,10 +57,10 @@ module Rubystats
|
|
57
57
|
def get_icdf(p)
|
58
58
|
check_range(p)
|
59
59
|
if p == 0.0
|
60
|
-
return -
|
60
|
+
return -MAX_VALUE
|
61
61
|
end
|
62
62
|
if p == 1.0
|
63
|
-
return
|
63
|
+
return MAX_VALUE
|
64
64
|
end
|
65
65
|
if p == 0.5
|
66
66
|
return @mean
|
@@ -72,8 +72,8 @@ module Rubystats
|
|
72
72
|
cdf_D_save = @cdf_denominator
|
73
73
|
@mean = 0.0
|
74
74
|
@variance = 1.0
|
75
|
-
@pdf_denominator = Math.sqrt(
|
76
|
-
@cdf_denominator =
|
75
|
+
@pdf_denominator = Math.sqrt(TWO_PI)
|
76
|
+
@cdf_denominator = SQRT2
|
77
77
|
x = find_root(p, 0.0, -100.0, 100.0)
|
78
78
|
#scale back
|
79
79
|
@mean = mean_save
|
@@ -1,6 +1,15 @@
|
|
1
1
|
require 'rubystats/modules'
|
2
2
|
|
3
3
|
module Rubystats
|
4
|
+
# The ProbabilityDistribution superclass provides an object
|
5
|
+
# for encapsulating probability distributions.
|
6
|
+
#
|
7
|
+
# Author: Jaco van Kooten
|
8
|
+
# Author: Mark Hale
|
9
|
+
# Author: Paul Meagher
|
10
|
+
# Author: Jesus Castagnetto
|
11
|
+
# Author: Bryan Donovan (port from PHPmath to Ruby)
|
12
|
+
|
4
13
|
class ProbabilityDistribution
|
5
14
|
include Rubystats::NumericalConstants
|
6
15
|
include Rubystats::SpecialMath
|
@@ -9,18 +18,21 @@ module Rubystats
|
|
9
18
|
def initialize
|
10
19
|
end
|
11
20
|
|
21
|
+
#returns the distribution mean
|
12
22
|
def mean
|
13
23
|
get_mean
|
14
24
|
end
|
15
25
|
|
16
|
-
|
26
|
+
#returns distribution variance
|
27
|
+
def variance
|
28
|
+
get_variance
|
17
29
|
end
|
18
30
|
|
19
|
-
|
31
|
+
#Probability density function
|
20
32
|
def pdf(x)
|
21
33
|
if x.class == Array
|
22
34
|
pdf_vals = []
|
23
|
-
for i in (0
|
35
|
+
for i in (0 ... x.length)
|
24
36
|
pdf_vals[i] = get_pdf(x[i])
|
25
37
|
end
|
26
38
|
return pdf_vals
|
@@ -29,9 +41,7 @@ module Rubystats
|
|
29
41
|
end
|
30
42
|
end
|
31
43
|
|
32
|
-
|
33
|
-
end
|
34
|
-
|
44
|
+
#Cummulative distribution function
|
35
45
|
def cdf(x)
|
36
46
|
if x.class == Array
|
37
47
|
cdf_vals = []
|
@@ -44,9 +54,7 @@ module Rubystats
|
|
44
54
|
end
|
45
55
|
end
|
46
56
|
|
47
|
-
|
48
|
-
end
|
49
|
-
|
57
|
+
#Inverse CDF
|
50
58
|
def icdf(p)
|
51
59
|
if p.class == Array
|
52
60
|
inv_vals = []
|
@@ -59,9 +67,7 @@ module Rubystats
|
|
59
67
|
end
|
60
68
|
end
|
61
69
|
|
62
|
-
|
63
|
-
end
|
64
|
-
|
70
|
+
#Returns random number(s) using subclass's get_rng method
|
65
71
|
def rng(n=1)
|
66
72
|
if n < 1
|
67
73
|
return "Number of random numbers to return must be 1 or greater"
|
@@ -77,12 +83,46 @@ module Rubystats
|
|
77
83
|
end
|
78
84
|
end
|
79
85
|
|
80
|
-
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
#private method to be implemented in subclass
|
90
|
+
def get_mean
|
91
|
+
end
|
92
|
+
|
93
|
+
#private method to be implemented in subclass
|
94
|
+
def get_variance
|
95
|
+
end
|
96
|
+
|
97
|
+
#private method to be implemented in subclass
|
98
|
+
#returns the probability that a stochastic variable x has the value X, i.e. P(x=X).
|
99
|
+
def get_pdf(x)
|
100
|
+
end
|
101
|
+
|
102
|
+
#private method to be implemented in subclass
|
103
|
+
#returns the probability that a stochastic variable x is less then X, i.e. P(x<X).
|
104
|
+
def get_cdf(x)
|
105
|
+
end
|
106
|
+
|
107
|
+
#private method to be implemented in subclass
|
108
|
+
#returns the value X for which P(x<X).
|
109
|
+
def get_icdf(p)
|
81
110
|
end
|
82
111
|
|
112
|
+
#private method to be implemented in subclass
|
113
|
+
#Random number generator
|
114
|
+
def get_rng
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
public
|
119
|
+
|
120
|
+
#check that variable is between lo and hi limits.
|
121
|
+
#lo default is 0.0 and hi default is 1.0
|
83
122
|
def check_range(x, lo=0.0, hi=1.0)
|
84
|
-
|
85
|
-
|
123
|
+
raise ArgumentError.new("x cannot be nil") if x.nil?
|
124
|
+
if x < lo or x > hi
|
125
|
+
raise ArgumentError.new("x must be less than lo (#{lo}) and greater than hi (#{hi})")
|
86
126
|
end
|
87
127
|
end
|
88
128
|
|
@@ -94,7 +134,7 @@ module Rubystats
|
|
94
134
|
end
|
95
135
|
end
|
96
136
|
|
97
|
-
def find_root
|
137
|
+
def find_root(prob, guess, x_lo, x_hi)
|
98
138
|
accuracy = 1.0e-10
|
99
139
|
max_iteration = 150
|
100
140
|
x = guess
|
data/test/tc_beta.rb
CHANGED
@@ -28,12 +28,17 @@ class TestBeta < Test::Unit::TestCase
|
|
28
28
|
0.956058132801147,
|
29
29
|
0.995358286711105,
|
30
30
|
0.99971672771575]
|
31
|
-
|
32
|
-
|
31
|
+
|
32
|
+
0.upto(x_vals.size - 1) do |i|
|
33
|
+
assert_in_delta expected_pvals[i], p_vals[i], 0.00000001
|
34
|
+
assert_in_delta expected_cvals[i], c_vals[i], 0.00000001
|
35
|
+
i += 1
|
36
|
+
end
|
37
|
+
|
33
38
|
x_vals.each do |x|
|
34
39
|
cdf = beta.cdf(x)
|
35
40
|
inv_cdf = beta.icdf(cdf)
|
36
|
-
assert_in_delta(x
|
41
|
+
assert_in_delta(x, inv_cdf, 0.00000001)
|
37
42
|
end
|
38
43
|
|
39
44
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rubystats/exponential_distribution'
|
4
|
+
|
5
|
+
class TestExponential < Test::Unit::TestCase
|
6
|
+
def test_simple
|
7
|
+
lmbda = 1
|
8
|
+
expd = Rubystats::ExponentialDistribution.new(lmbda)
|
9
|
+
assert_equal(1, expd.mean)
|
10
|
+
assert_equal(1, expd.variance)
|
11
|
+
assert_in_delta(0.13533528323661, expd.pdf(2), 0.00000001)
|
12
|
+
assert_in_delta(0.95021293163214, expd.cdf(3), 0.00000001)
|
13
|
+
assert_in_delta(2.9997402949515, expd.icdf(0.9502), 0.00000001)
|
14
|
+
assert !expd.rng.nil?
|
15
|
+
# make sure the mean of RNG values is close to the expected mean
|
16
|
+
rngs = []
|
17
|
+
rngsum = 0
|
18
|
+
n = 5000
|
19
|
+
n.times do
|
20
|
+
rng = expd.rng
|
21
|
+
rngs << rng
|
22
|
+
rngsum += rng
|
23
|
+
end
|
24
|
+
avg = rngsum / n
|
25
|
+
assert_in_delta(avg, 1, 0.1)
|
26
|
+
|
27
|
+
x_vals = [0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5]
|
28
|
+
p_vals = expd.pdf(x_vals)
|
29
|
+
|
30
|
+
c_vals = expd.cdf(x_vals)
|
31
|
+
expected_pvals = [1.0,
|
32
|
+
0.60653065971263,
|
33
|
+
0.36787944117144,
|
34
|
+
0.22313016014843,
|
35
|
+
0.13533528323661,
|
36
|
+
0.082084998623899,
|
37
|
+
0.049787068367864,
|
38
|
+
0.030197383422319 ]
|
39
|
+
expected_cvals = [0.0,
|
40
|
+
0.39346934028737,
|
41
|
+
0.63212055882856,
|
42
|
+
0.77686983985157,
|
43
|
+
0.86466471676339,
|
44
|
+
0.9179150013761,
|
45
|
+
0.95021293163214,
|
46
|
+
0.96980261657768 ]
|
47
|
+
|
48
|
+
0.upto(x_vals.size - 1) do |i|
|
49
|
+
assert_in_delta expected_pvals[i], p_vals[i], 0.00000001
|
50
|
+
assert_in_delta expected_cvals[i], c_vals[i], 0.00000001
|
51
|
+
i += 1
|
52
|
+
end
|
53
|
+
|
54
|
+
x_vals.each do |x|
|
55
|
+
cdf = expd.cdf(x)
|
56
|
+
inv_cdf = expd.icdf(cdf)
|
57
|
+
assert_in_delta(x, inv_cdf, 0.00000001)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/test/tc_require_all.rb
CHANGED
data/test/ts_stats.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubystats
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan Donovan - http://www.bryandonovan.com
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-05-
|
12
|
+
date: 2008-05-09 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -38,18 +38,21 @@ files:
|
|
38
38
|
- Rakefile
|
39
39
|
- examples/beta.rb
|
40
40
|
- examples/binomial.rb
|
41
|
+
- examples/exponential.rb
|
41
42
|
- examples/failrate_vs_goal.rb
|
42
43
|
- examples/fisher.rb
|
43
44
|
- examples/norm.rb
|
44
45
|
- lib/rubystats.rb
|
45
46
|
- lib/rubystats/beta_distribution.rb
|
46
47
|
- lib/rubystats/binomial_distribution.rb
|
48
|
+
- lib/rubystats/exponential_distribution.rb
|
47
49
|
- lib/rubystats/fishers_exact_test.rb
|
48
50
|
- lib/rubystats/modules.rb
|
49
51
|
- lib/rubystats/normal_distribution.rb
|
50
52
|
- lib/rubystats/probability_distribution.rb
|
51
53
|
- test/tc_beta.rb
|
52
54
|
- test/tc_binomial.rb
|
55
|
+
- test/tc_exponential.rb
|
53
56
|
- test/tc_fisher.rb
|
54
57
|
- test/tc_norm.rb
|
55
58
|
- test/tc_require_all.rb
|