accumulators 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -2,7 +2,7 @@ GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
4
  diff-lcs (1.1.2)
5
- ffi (1.0.8)
5
+ ffi (1.0.9)
6
6
  git (1.2.5)
7
7
  growl (1.0.3)
8
8
  guard (0.3.4)
@@ -13,8 +13,8 @@ GEM
13
13
  bundler (~> 1.0.0)
14
14
  git (>= 1.2.5)
15
15
  rake
16
- libnotify (0.3.0)
17
- ffi (>= 0.6.2)
16
+ libnotify (0.5.2)
17
+ ffi (~> 1.0)
18
18
  rake (0.9.0)
19
19
  rb-fsevent (0.4.0)
20
20
  rb-inotify (0.8.4)
@@ -24,7 +24,7 @@ GEM
24
24
  rspec-core (~> 2.6.0)
25
25
  rspec-expectations (~> 2.6.0)
26
26
  rspec-mocks (~> 2.6.0)
27
- rspec-core (2.6.1)
27
+ rspec-core (2.6.2)
28
28
  rspec-expectations (2.6.0)
29
29
  diff-lcs (~> 1.1.2)
30
30
  rspec-mocks (2.6.0)
data/Guardfile CHANGED
@@ -6,9 +6,4 @@ guard 'rspec', :version => 2 do
6
6
  watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
7
  watch('spec/spec_helper.rb') { "spec" }
8
8
 
9
- # Rails example
10
- watch(%r{^spec/.+_spec\.rb})
11
- watch(%r{^app/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
12
- watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
13
- watch(%r{^app/controllers/(.+)_(controller)\.rb}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
14
9
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.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.2.0"
8
+ s.version = "0.3.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"]
@@ -27,16 +27,13 @@ Gem::Specification.new do |s|
27
27
  "Rakefile",
28
28
  "VERSION",
29
29
  "accumulators.gemspec",
30
- "features/accumulators.feature",
31
- "features/step_definitions/accumulators_steps.rb",
32
- "features/support/env.rb",
33
30
  "lib/accumulators.rb",
34
31
  "lib/accumulators/count.rb",
35
32
  "lib/accumulators/mean.rb",
36
- "lib/accumulators/meanvariance.rb",
37
- "spec/accumulators/count_spec.rb",
38
- "spec/accumulators/mean_spec.rb",
39
- "spec/accumulators/meanvariance_spec.rb",
33
+ "lib/accumulators/mean_variance.rb",
34
+ "spec/lib/accumulators/count_spec.rb",
35
+ "spec/lib/accumulators/mean_spec.rb",
36
+ "spec/lib/accumulators/mean_variance_spec.rb",
40
37
  "spec/spec_helper.rb"
41
38
  ]
42
39
  s.homepage = %q{http://github.com/hgavin/accumulators}
data/lib/accumulators.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Accumulators
2
2
  autoload :Count, "accumulators/count"
3
3
  autoload :Mean, "accumulators/mean"
4
- autoload :MeanVariance, "accumulators/meanvariance"
4
+ autoload :MeanVariance, "accumulators/mean_variance"
5
5
  end
6
6
 
@@ -19,7 +19,7 @@ module Accumulators
19
19
  @count = @count + rhs.count
20
20
  @mean = (sum + rhs_sum) / @count
21
21
  else
22
- raise ArgumentError.new("Can only add numbers to a Mean Accumulator")
22
+ raise ArgumentError.new("You may not add #{rhs.class} to #{self.class}")
23
23
  end
24
24
  end
25
25
  end
@@ -28,16 +28,24 @@ module Accumulators
28
28
  @sumsq = newSumsq
29
29
  end
30
30
  else
31
- raise ArgumentError
31
+ raise ArgumentError.new("You may not add #{rhs.class} to #{self.class}")
32
32
  end
33
33
  end
34
34
 
35
- def variance
36
- @count > 1 ? (@sumsq / (@count)) : 0.0
35
+ def variance(options = {})
36
+ if options[:type] and not [:sample, :population].include? options[:type]
37
+ raise ArgumentError.new("type must be one of :sample, :population")
38
+ end
39
+
40
+ if options[:type] == :population
41
+ @count > 1 ? (@sumsq / (@count)) : 0.0
42
+ else
43
+ @count > 1 ? (@sumsq / (@count + 1)) : 0.0
44
+ end
37
45
  end
38
46
 
39
- def stddev
40
- Math.sqrt(variance)
47
+ def stddev(options = {})
48
+ Math.sqrt(variance(options))
41
49
  end
42
50
 
43
51
  end
@@ -1,60 +1,58 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "Accumulators" do
4
- describe "Count" do
5
- before :each do
6
- @count = Accumulators::Count.new
7
- end
3
+ module Accumulators
4
+ describe Count do
5
+ let(:count){Count.new}
8
6
 
9
7
  context "Creation" do
10
8
  it "can be created" do
11
- lambda{ Accumulators::Count.new }.should_not raise_error
9
+ lambda{ Count.new }.should_not raise_error
12
10
  end
13
11
 
14
12
  it "returns count of 0 before anything is added to it" do
15
- Accumulators::Count.new.count.should == 0
13
+ Count.new.count.should == 0
16
14
  end
17
15
  end
18
16
 
19
17
  context "adding numbers or distributions" do
20
18
  it "allows integers to be added" do
21
- lambda{@count.add 5}.should_not raise_error
19
+ lambda{count.add 5}.should_not raise_error
22
20
  end
23
21
 
24
22
  it "allows floats to be added" do
25
- lambda{@count.add 3.4}.should_not raise_error
23
+ lambda{count.add 3.4}.should_not raise_error
26
24
  end
27
25
 
28
26
  it "allows other Count distributions to be added" do
29
- c2 = Accumulators::Count.new
30
- lambda{@count.add c2}.should_not raise_error
27
+ c2 = Count.new
28
+ lambda{count.add c2}.should_not raise_error
31
29
  end
32
30
 
33
31
  it "allows strings to be added" do
34
- lambda{@count.add "1.5"}.should_not raise_error
32
+ lambda{count.add "1.5"}.should_not raise_error
35
33
  end
36
34
  end
37
35
 
38
36
  context "correctness of item additions" do
39
37
  it "should return a count of 1 when a single item is added" do
40
- @count.add 5
41
- @count.count.should == 1
38
+ count.add 5
39
+ count.count.should == 1
42
40
  end
43
41
 
44
42
  it "should return the count of how many items have been added" do
45
43
  1.upto(1000) do |i|
46
- @count.add i
47
- @count.count.should == i
44
+ count.add i
45
+ count.count.should == i
48
46
  end
49
47
  end
50
48
  end
51
49
 
52
50
  context "correctness of accumulator additions" do
53
51
  it "should combine two Count accumulators correctly" do
54
- c2 = Accumulators::Count.new
55
- 10.times{ c2.add 1; @count.add 1 }
56
- @count.add(c2)
57
- @count.count.should == 20
52
+ c2 = Count.new
53
+ 10.times{ c2.add 1; count.add 1 }
54
+ count.add(c2)
55
+ count.count.should == 20
58
56
  end
59
57
  end
60
58
  end
@@ -1,96 +1,96 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe "Accumulators" do
4
- describe "Mean" do
5
- before :each do
6
- @mean = Accumulators::Mean.new
7
- end
3
+ module Accumulators
4
+ describe Mean do
5
+ let(:mean){Mean.new}
8
6
 
9
7
  context "Creation" do
10
8
  it "can be created" do
11
- lambda{ Accumulators::Mean.new}.should_not raise_error
9
+ lambda{ Mean.new}.should_not raise_error
12
10
  end
13
11
 
14
12
  it "returns count and mean of 0 before anything is added to it" do
15
- @mean.count.should == 0
16
- @mean.mean.should be_within(EPSILON).of(0.0)
13
+ mean.count.should == 0
14
+ mean.mean.should be_within(EPSILON).of(0.0)
17
15
  end
18
16
 
19
17
  end
20
18
 
21
19
  context "adding numbers or distributions" do
22
20
  it "allows integers to be added" do
23
- lambda{@mean.add 5}.should_not raise_error
21
+ lambda{mean.add 5}.should_not raise_error
24
22
  end
25
23
 
26
24
  it "allows floats to be added" do
27
- lambda{@mean.add 3.4}.should_not raise_error
25
+ lambda{mean.add 3.4}.should_not raise_error
28
26
  end
29
27
 
30
28
  it "allows other Mean distributions to be added" do
31
- mean2 = Accumulators::Mean.new
32
- lambda{@mean.add mean2}.should_not raise_error
29
+ mean2 = Mean.new
30
+ lambda{mean.add mean2}.should_not raise_error
33
31
  end
34
32
 
35
33
  it "raises an ArgumentError if a string is added" do
36
- lambda{@mean.add "1.5"}.should raise_error(ArgumentError)
34
+ lambda{mean.add "1.5"}.should raise_error(
35
+ ArgumentError,
36
+ "You may not add String to Accumulators::Mean")
37
37
  end
38
38
  end
39
39
 
40
40
  context "correctness of int additions" do
41
41
  it "should return count of 1 and mean of 5 when 5 is added" do
42
- @mean.add(5)
43
- @mean.count.should == 1
44
- @mean.mean.should be_within(EPSILON).of(5)
42
+ mean.add(5)
43
+ mean.count.should == 1
44
+ mean.mean.should be_within(EPSILON).of(5)
45
45
  end
46
46
 
47
47
  it "should calculate the mean correctly for a set of integers" do
48
- 1.upto(10) {|i| @mean.add i}
49
- @mean.count.should == 10
50
- @mean.mean.should be_within(EPSILON).of((1..10).reduce(:+).to_f/10)
48
+ 1.upto(10) {|i| mean.add i}
49
+ mean.count.should == 10
50
+ mean.mean.should be_within(EPSILON).of((1..10).reduce(:+).to_f/10)
51
51
  end
52
52
 
53
53
  it "should calculate the mean correctly for a random set of 1000 integers" do
54
54
  vals = []
55
55
  1000.times do
56
56
  vals << rand(100000)
57
- @mean.add(vals.last)
57
+ mean.add(vals.last)
58
58
  end
59
59
 
60
- @mean.mean.should be_within(EPSILON).of(vals.reduce(:+).to_f/vals.size)
60
+ mean.mean.should be_within(EPSILON).of(vals.reduce(:+).to_f/vals.size)
61
61
  end
62
62
  end
63
63
 
64
64
  context "correctness of float additions" do
65
65
  it "should calculate the mean correctly for a set of floats" do
66
- 1.upto(10) {|i| @mean.add i+0.1}
67
- @mean.count.should == 10
68
- @mean.mean.should be_within(EPSILON).of((1..10).map{|i| i+0.1}.reduce(:+)/10)
66
+ 1.upto(10) {|i| mean.add i+0.1}
67
+ mean.count.should == 10
68
+ mean.mean.should be_within(EPSILON).of((1..10).map{|i| i+0.1}.reduce(:+)/10)
69
69
  end
70
70
 
71
71
  it "should calculate the mean correctly for a random set of 1000 floats" do
72
72
  vals = []
73
73
  1000.times do
74
74
  vals << rand * 1000000
75
- @mean.add vals.last
75
+ mean.add vals.last
76
76
  end
77
- @mean.mean.should be_within(EPSILON).of(vals.reduce(:+)/vals.size)
77
+ mean.mean.should be_within(EPSILON).of(vals.reduce(:+)/vals.size)
78
78
  end
79
79
  end
80
80
 
81
81
  context "correctness of accumulator additions" do
82
82
  it "should combine two means correctly" do
83
- m2 = Accumulators::Mean.new
83
+ m2 = Mean.new
84
84
  vals = []
85
85
  500.times do
86
86
  vals << rand * 1000000
87
- @mean.add vals.last
87
+ mean.add vals.last
88
88
  vals << rand * 100000
89
89
  m2.add vals.last
90
90
  end
91
- @mean.add(m2)
92
- @mean.count.should == 1000
93
- @mean.mean.should be_within(EPSILON).of(vals.reduce(:+)/vals.size)
91
+ mean.add(m2)
92
+ mean.count.should == 1000
93
+ mean.mean.should be_within(EPSILON).of(vals.reduce(:+)/vals.size)
94
94
  end
95
95
  end
96
96
  end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ module Accumulators
4
+ describe MeanVariance do
5
+ let(:meanvar){MeanVariance.new}
6
+
7
+ context "When creating" do
8
+ it "can be created" do
9
+ lambda{ MeanVariance.new }.should_not raise_error
10
+ end
11
+
12
+ it "returns count,mean,var of 0,0.0,0.0 before anything is added" do
13
+ meanvar.count.should == 0
14
+ meanvar.mean.should be_within(EPSILON).of(0.0)
15
+ meanvar.variance(type: :population).should be_within(EPSILON).of(0.0)
16
+ end
17
+ end
18
+
19
+ context "When adding numbers or distributions" do
20
+ it "allows integers to be added" do
21
+ lambda{ meanvar.add 5 }.should_not raise_error
22
+ end
23
+
24
+ it "allows floats to be added" do
25
+ lambda{ meanvar.add 5.5 }.should_not raise_error
26
+ end
27
+
28
+ it "allows other MeanVar distributions to be added" do
29
+ lambda{ meanvar.add MeanVariance.new }.should_not raise_error
30
+ end
31
+
32
+ it "raises an ArgumentError if a string is added" do
33
+ lambda{ meanvar.add "1.5" }.should raise_error(
34
+ ArgumentError,
35
+ "You may not add String to Accumulators::MeanVariance")
36
+ end
37
+
38
+ it "raises an ArgumentError if a Mean accumulator is added" do
39
+ lambda{ meanvar.add Mean.new }.should raise_error(
40
+ ArgumentError,
41
+ "You may not add Accumulators::Mean to Accumulators::MeanVariance")
42
+ end
43
+
44
+ it "raises an ArgumentError if an unknown type of variance is requested" do
45
+ lambda{ meanvar.variance(type: :unknown) }.should raise_error(
46
+ ArgumentError,
47
+ "type must be one of :sample, :population")
48
+ end
49
+ end
50
+
51
+ context "When checking correctness of biased/population calculations" do
52
+ before do
53
+ @vals = []
54
+ 1000.times do
55
+ @vals << rand * 10000
56
+ meanvar.add @vals.last
57
+ end
58
+ end
59
+
60
+ it "calculates the count and mean correctly for a set of numbers" do
61
+ meanvar.count.should == @vals.size
62
+ meanvar.mean.should be_within(EPSILON).of(@vals.reduce(:+)/@vals.size)
63
+ end
64
+
65
+ it "calculates the population variance and stddev correctly" do
66
+ variance = @vals.map{|v| (v - meanvar.mean)**2}.reduce(:+) / @vals.size
67
+ meanvar.variance(type: :population).should be_within(EPSILON).of(variance)
68
+ meanvar.stddev(type: :population).should be_within(EPSILON).of(Math.sqrt(variance))
69
+ end
70
+
71
+ it "calculates the sample variance and stddev correctly" do
72
+ variance = @vals.map{|v| (v - meanvar.mean)**2}.reduce(:+) / (@vals.size + 1)
73
+ meanvar.variance(type: :sample).should be_within(EPSILON).of(variance)
74
+ meanvar.stddev(type: :sample).should be_within(EPSILON).of(Math.sqrt(variance))
75
+ end
76
+
77
+ it "defaults to sample variance" do
78
+ meanvar.variance.should be_within(EPSILON).of(meanvar.variance(type: :sample))
79
+ end
80
+ end
81
+
82
+ context "When combining MeanVariances" do
83
+ it "combines two MeanVariances correctly" do
84
+ vals = []
85
+ mv2 = MeanVariance.new
86
+ 500.times do
87
+ vals << rand * 10000
88
+ meanvar.add vals.last
89
+ vals << rand * 1000
90
+ mv2.add vals.last
91
+ end
92
+
93
+ meanvar.add(mv2)
94
+
95
+ meanvar.count.should == vals.size
96
+ meanvar.mean.should be_within(EPSILON).of(vals.reduce(:+)/vals.size)
97
+ meanvar.variance(type: :population).should be_within(EPSILON).of(vals.map{|v| (v - meanvar.mean)**2}.reduce(:+) / vals.size)
98
+ end
99
+ end
100
+
101
+ end
102
+ end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: accumulators
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.0
5
+ version: 0.3.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Gavin Heavyside
@@ -99,16 +99,13 @@ files:
99
99
  - Rakefile
100
100
  - VERSION
101
101
  - accumulators.gemspec
102
- - features/accumulators.feature
103
- - features/step_definitions/accumulators_steps.rb
104
- - features/support/env.rb
105
102
  - lib/accumulators.rb
106
103
  - lib/accumulators/count.rb
107
104
  - lib/accumulators/mean.rb
108
- - lib/accumulators/meanvariance.rb
109
- - spec/accumulators/count_spec.rb
110
- - spec/accumulators/mean_spec.rb
111
- - spec/accumulators/meanvariance_spec.rb
105
+ - lib/accumulators/mean_variance.rb
106
+ - spec/lib/accumulators/count_spec.rb
107
+ - spec/lib/accumulators/mean_spec.rb
108
+ - spec/lib/accumulators/mean_variance_spec.rb
112
109
  - spec/spec_helper.rb
113
110
  has_rdoc: true
114
111
  homepage: http://github.com/hgavin/accumulators
@@ -124,7 +121,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
124
121
  requirements:
125
122
  - - ">="
126
123
  - !ruby/object:Gem::Version
127
- hash: -274752833993731131
124
+ hash: -417395174434128828
128
125
  segments:
129
126
  - 0
130
127
  version: "0"
@@ -1,9 +0,0 @@
1
- Feature: something something
2
- In order to something something
3
- A user something something
4
- something something something
5
-
6
- Scenario: something something
7
- Given inspiration
8
- When I create a sweet new gem
9
- Then everyone should see how awesome I am
File without changes
@@ -1,13 +0,0 @@
1
- require 'bundler'
2
- begin
3
- Bundler.setup(:default, :development)
4
- rescue Bundler::BundlerError => e
5
- $stderr.puts e.message
6
- $stderr.puts "Run `bundle install` to install missing gems"
7
- exit e.status_code
8
- end
9
-
10
- $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
11
- require 'accumulators'
12
-
13
- require 'rspec/expectations'
@@ -1,78 +0,0 @@
1
- require 'spec_helper'
2
-
3
-
4
- describe "Accumulators" do
5
- describe "MeanVariance" do
6
- before :each do
7
- @meanvar = Accumulators::MeanVariance.new
8
- end
9
-
10
- context "Creation" do
11
- it "can be created" do
12
- lambda{ Accumulators::MeanVariance.new }.should_not raise_error
13
- end
14
-
15
- it "returns count,mean,var of 0,0.0,0.0 before anything is added" do
16
- @meanvar.count.should == 0
17
- @meanvar.mean.should be_within(EPSILON).of(0.0)
18
- @meanvar.variance.should be_within(EPSILON).of(0.0)
19
- end
20
- end
21
-
22
- context "adding numbers or distributions" do
23
- it "allows integers to be added" do
24
- lambda{ @meanvar.add 5 }.should_not raise_error
25
- end
26
-
27
- it "allows floats to be added" do
28
- lambda{ @meanvar.add 5.5 }.should_not raise_error
29
- end
30
-
31
- it "allows other MeanVar distributions to be added" do
32
- lambda{ @meanvar.add Accumulators::MeanVariance.new }.should_not raise_error
33
- end
34
-
35
- it "raises an ArgumentError if a string is added" do
36
- lambda{ @meanvar.add "1.5" }.should raise_error(ArgumentError)
37
- end
38
-
39
- it "raises an ArgumentError if a Mean accumulator is added" do
40
- lambda{ @meanvar.add Accumulators::Mean.new }.should raise_error(ArgumentError)
41
- end
42
- end
43
-
44
- context "correctness of calcs when adding numbers" do
45
- it "should calculate the mean and variance correctly for a set of numbers" do
46
- vals = []
47
- 1000.times do
48
- vals << rand * 10000
49
- @meanvar.add vals.last
50
- end
51
-
52
- @meanvar.count.should == vals.size
53
- @meanvar.mean.should be_within(EPSILON).of(vals.reduce(:+)/vals.size)
54
- @meanvar.variance.should be_within(EPSILON).of(vals.map{|v| (v - @meanvar.mean)**2}.reduce(:+) / vals.size)
55
- end
56
- end
57
-
58
- context "correctness of calcs when adding MeanVariance accumulators" do
59
- it "should combine two MeanVariances correctly" do
60
- vals = []
61
- mv2 = Accumulators::MeanVariance.new
62
- 500.times do
63
- vals << rand * 10000
64
- @meanvar.add vals.last
65
- vals << rand * 1000
66
- mv2.add vals.last
67
- end
68
-
69
- @meanvar.add(mv2)
70
-
71
- @meanvar.count.should == vals.size
72
- @meanvar.mean.should be_within(EPSILON).of(vals.reduce(:+)/vals.size)
73
- @meanvar.variance.should be_within(EPSILON).of(vals.map{|v| (v - @meanvar.mean)**2}.reduce(:+) / vals.size)
74
- end
75
- end
76
-
77
- end
78
- end