accumulators 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,10 +2,23 @@ accumulators
2
2
  ============
3
3
 
4
4
  A set of statistical accumulators for Ruby. There is a range of containers for
5
- different measures, such as count, mean, and mean-variance. You can add values to
6
- the containers, and ask for their respective statistical measures. The accumulators
7
- use incremental algorithms to update their measures with each addition, so you can
8
- add lots of values without needing lots of memory.
5
+ different measures, such as count, sum, mean, and mean-variance. You can add values to
6
+ the containers, and ask for their respective statistical measures.
7
+
8
+ Where appropriate the accumulators use incremental algorithms to update their
9
+ measures with each addition, so you can add lots of values without needing lots of
10
+ memory. (see http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm)
11
+
12
+ The accumulators can be combined. e.g. if you have two mean-variance
13
+ accumulators, each of which has their own mean and variance, you can add them
14
+ together to get the mean and variance of the combined samples.
15
+
16
+ Always remember that floating-point arithmetic is not precise, so if you are
17
+ using these accumulators for anything important, and especially if you are
18
+ accumulating lots of samples, you should run your own tests on the accuracy of
19
+ the calculations. I am not aware of any significant issues, but I make no promises
20
+ and provide no assurances as to the accuracy or stability of these
21
+ calculations.
9
22
 
10
23
  Installation
11
24
  ------------
@@ -16,31 +29,75 @@ Example Usage
16
29
 
17
30
  $ irb
18
31
  >> require 'accumulators'
19
- >> mean = Accumulators::Mean.new
20
- >> mean.add 1
21
- >> mean.add 2
22
- >> mean.add 3
23
- >> mean.add 4
24
- >> mean.count
32
+ >> meanvar = Accumulators:MeanVariance.new
33
+ >> meanvar.add 1
34
+ >> meanvar.add 2
35
+ >> meanvar.add 3
36
+ >> meanvar.add 4
37
+ >> meanvar.count
25
38
  => 4
26
- >> mean.mean
39
+ >> meanvar.mean
27
40
  => 2.5
41
+ >> meanvar.variance
42
+ => 1.0
43
+ >> meanvar.variance(type: :sample)
44
+ => 1.0
45
+ >> meanvar.variance(type: :population)
46
+ => 1.25
47
+ >> meanvar.stddev
48
+ => 1.0
49
+ >> meanvar.stddev(type: :population)
50
+ => 1.118033988749895
51
+
52
+ Example of combining accumulators
53
+ ---------------------------------
54
+ Accumulators of the same type can be added together. Here we will add three
55
+ numbers to one mean-variance accumulator, three to another, and show that their
56
+ combined mean and variance is equal to that of the single accumulator which
57
+ saw all the values, within the usual constraints of floating-point arithmetic.
58
+
59
+ >> mv1 = Accumulators::MeanVariance.new # sees the first 3 values
60
+ >> mv2 = Accumulators::MeanVariance.new # sees the second 3 values
61
+ >> mv = Accumulators::MeanVariance.new # sees all values
62
+ >>
63
+ >> [1.1, 2.2, 3.3].each {|n| mv1.add n; mv.add n}
64
+ >> [4.4, 5.5, 6.6].each {|n| mv2.add n; mv.add n}
65
+ >>
66
+ >> mv1.mean
67
+ => 2.2
68
+ >> mv1.variance
69
+ => 0.6049999999999998
70
+ >>
71
+ >> mv2.mean
72
+ => 5.5
73
+ >> mv2.variance
74
+ => 0.6049999999999998
75
+ >>
76
+ >> mv.mean
77
+ => 3.8499999999999996
78
+ >> mv.variance
79
+ => 3.025
80
+ >>
81
+ >> mv1.add mv2
82
+ >> mv1.mean
83
+ => 3.8499999999999996
84
+ >> mv1.variance
85
+ >> 3.0249999999999995 # close to 3.025 - discrepancy from floating-point
28
86
 
29
87
  Available accumulators
30
88
  ----------------------
31
89
 
32
90
  * Count
91
+ * Sum
33
92
  * Mean
34
93
  * MeanVariance
35
94
 
36
95
  TODO
37
96
  ----
38
97
 
39
- * Allow choosing between biased & unbiased variance/standard devation
40
98
  * Skew?
41
99
  * Weighted Means
42
100
  * min, max, and min-max
43
- * sum
44
101
 
45
102
  Contributing to accumulators
46
103
  ----------------------------
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.0
data/accumulators.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{accumulators}
8
- s.version = "0.3.0"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Gavin Heavyside"]
@@ -31,9 +31,11 @@ Gem::Specification.new do |s|
31
31
  "lib/accumulators/count.rb",
32
32
  "lib/accumulators/mean.rb",
33
33
  "lib/accumulators/mean_variance.rb",
34
+ "lib/accumulators/sum.rb",
34
35
  "spec/lib/accumulators/count_spec.rb",
35
36
  "spec/lib/accumulators/mean_spec.rb",
36
37
  "spec/lib/accumulators/mean_variance_spec.rb",
38
+ "spec/lib/accumulators/sum_spec.rb",
37
39
  "spec/spec_helper.rb"
38
40
  ]
39
41
  s.homepage = %q{http://github.com/hgavin/accumulators}
data/lib/accumulators.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  module Accumulators
2
2
  autoload :Count, "accumulators/count"
3
+ autoload :Sum, "accumulators/sum"
3
4
  autoload :Mean, "accumulators/mean"
4
5
  autoload :MeanVariance, "accumulators/mean_variance"
5
6
  end
@@ -0,0 +1,19 @@
1
+ module Accumulators
2
+ class Sum
3
+ attr_reader :sum
4
+
5
+ def initialize
6
+ @sum = 0
7
+ end
8
+
9
+ def add(rhs)
10
+ if rhs.is_a? Numeric
11
+ @sum += rhs
12
+ elsif rhs.is_a? self.class
13
+ @sum += rhs.sum
14
+ else
15
+ raise ArgumentError.new("You may not add #{rhs.class} to #{self.class}")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ module Accumulators
4
+ describe Sum do
5
+ let(:sum){ Sum.new }
6
+
7
+ context "Creation" do
8
+ it "can be created" do
9
+ lambda{ Sum.new }.should_not raise_error
10
+ end
11
+
12
+ it "returns a sum of 0 before anything is added to it" do
13
+ sum.sum.should == 0
14
+ end
15
+ end
16
+
17
+ context "adding numbers or distributions" do
18
+ it "allows integers to be added" do
19
+ lambda { sum.add 5 }.should_not raise_error
20
+ end
21
+
22
+ it "allows floats to be added" do
23
+ lambda { sum.add 3.4 }.should_not raise_error
24
+ end
25
+
26
+ it "allows other Sum distributions to be added" do
27
+ lambda { sum.add Sum.new }.should_not raise_error
28
+ end
29
+
30
+ it "raises an ArgumentError if a String is added" do
31
+ lambda { sum.add "1.5" }.should raise_error(
32
+ ArgumentError,
33
+ "You may not add String to Accumulators::Sum")
34
+ end
35
+ end
36
+
37
+ context "Correctness of int additions" do
38
+ it "should return an Integer 6 when 1,2,3 is added" do
39
+ (1..3).each{ |i| sum.add i }
40
+
41
+ sum.sum.should be_a Integer
42
+ sum.sum.should == 6
43
+ end
44
+
45
+ it "should calculate the sum correctly for a set of 1000 random integers" do
46
+ vals = []
47
+ 1000.times do
48
+ vals << rand(100000)
49
+ sum.add vals.last
50
+ end
51
+ sum.sum.should be_a Integer
52
+ sum.sum.should == vals.reduce(:+)
53
+ end
54
+ end
55
+
56
+ context "Correctness of float additions" do
57
+ it "should return a Float 6.1 when 1.1, 2.8, 2.2 is added" do
58
+ [1.1,2.8,2.2].each{|f| sum.add f}
59
+
60
+ sum.sum.should be_a Float
61
+ sum.sum.should be_within(EPSILON).of(6.1)
62
+ end
63
+
64
+ it "should calculate the sum correctly for a set of 1000 random floats" do
65
+ vals = []
66
+ 1000.times do
67
+ vals << rand * 1000000
68
+ sum.add vals.last
69
+ end
70
+
71
+ sum.sum.should be_a Float
72
+ sum.sum.should be_within(EPSILON).of(vals.reduce(:+))
73
+ end
74
+ end
75
+
76
+ context "Correctness of accumulator additions" do
77
+ it "combines two sums correctly" do
78
+ s2 = Sum.new
79
+ vals = []
80
+ 500.times do
81
+ vals << rand * 1000*1000
82
+ sum.add vals.last
83
+ vals << rand * 100*1000
84
+ s2.add vals.last
85
+ end
86
+
87
+ sum.add(s2)
88
+ sum.sum.should be_a Float
89
+ sum.sum.should be_within(EPSILON).of(vals.reduce(:+))
90
+ end
91
+ end
92
+ end
93
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: accumulators
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.0
5
+ version: 0.4.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Gavin Heavyside
@@ -103,9 +103,11 @@ files:
103
103
  - lib/accumulators/count.rb
104
104
  - lib/accumulators/mean.rb
105
105
  - lib/accumulators/mean_variance.rb
106
+ - lib/accumulators/sum.rb
106
107
  - spec/lib/accumulators/count_spec.rb
107
108
  - spec/lib/accumulators/mean_spec.rb
108
109
  - spec/lib/accumulators/mean_variance_spec.rb
110
+ - spec/lib/accumulators/sum_spec.rb
109
111
  - spec/spec_helper.rb
110
112
  has_rdoc: true
111
113
  homepage: http://github.com/hgavin/accumulators
@@ -121,7 +123,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
121
123
  requirements:
122
124
  - - ">="
123
125
  - !ruby/object:Gem::Version
124
- hash: -417395174434128828
126
+ hash: -3603142917674474649
125
127
  segments:
126
128
  - 0
127
129
  version: "0"