rubystats 0.2.6 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2789811064d35c08bdf8aa20530b392515d065f6
4
- data.tar.gz: b148705e2926210b822f42af9e2b51eddedce116
3
+ metadata.gz: 594c482d4bcbf6954516475851e5d8361eb171e6
4
+ data.tar.gz: 89bb13f0241a4a42439099c37d4f2500f64b8519
5
5
  SHA512:
6
- metadata.gz: 817f2c326fbf480121f3f29f909ea04634cdf404240e17c1517f70443d4033b0dd5853974c3889e1facaa801c951361d5f36a8775fe65ee3e553c551b5685682
7
- data.tar.gz: e2bc90eed10e16455dbb2721e3d101dd543b0ff2bf7cc4ee255ea540788770ea4ab98290e7169b246a5daa49cbceca7080732da5b8e01746c079581fa558bb0e
6
+ metadata.gz: 34a76aa78895d6fc605660d72b8e7602c1dd85150132b1bef2969c438cac22c1c91425cf1c3599b3202a43bc5a644444c31e30d9d181c8894cdfa2a70755da89
7
+ data.tar.gz: 12836502065954197f8c097060794f968d5845e9e9460c6ce175b91df04a569050f26a69855bee7803136661774c0aa39921aff2fe57f89b95de53ef4089782e
@@ -1,6 +1,8 @@
1
1
  sudo: false
2
2
  cache: bundler
3
3
  language: ruby
4
+ before_install:
5
+ - gem install bundler
4
6
  before_script:
5
7
  - 'echo ''gem: --no-ri --no-rdoc'' > ~/.gemrc' # skip installing docs for gems
6
8
  script: 'bundle exec rake test'
@@ -1,6 +1,6 @@
1
1
  = Rubystats
2
2
 
3
- * http://rubyforge.org/projects/rubystats/
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.0733813315868699
71
+ PDF(11): 0.17603266338214973
61
72
 
62
73
  === Example: get some random numbers from a normal distribution
63
74
 
@@ -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
@@ -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
@@ -85,5 +85,9 @@ module Rubystats
85
85
  end
86
86
  end
87
87
 
88
+ def rng
89
+ self.icdf(rand)
90
+ end
91
+
88
92
  end
89
93
  end
@@ -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 pdf(_x)
54
- if _x.class == Array
55
- pdf_vals = []
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
- return sum
73
+ sum
132
74
  end
133
75
 
134
- # Private binomial RNG function
135
- # Original version of this function from Press et al.
136
- #
137
- # see http://www.library.cornell.edu/nr/bookcpdf/c7-3.pdf
138
- #
139
- # Changed parts having to do with generating a uniformly distributed
140
- # number in the 0 to 1 range. Also using instance variables, instead
141
- # of supplying function with p and n values. Finally calling port
142
- # of JSci's log gamma routine instead of Press et al.
143
- #
144
- # There are enough non-trivial changes to this function that the
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