simple_stats 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
6
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - jruby-18mode # JRuby in 1.8 mode
7
+ - jruby-19mode # JRuby in 1.9 mode
8
+ - rbx-18mode
9
+ - rbx-19mode # currently in active development, may or may not work for your project
10
+ # uncomment this line if your project needs to run something other than `rake`:
11
+ script: bundle exec rspec spec
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in simple_stats.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec'
data/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # SimpleStats [![Build Status](https://secure.travis-ci.org/brianhempel/simple_stats.png)](http://travis-ci.org/brianhempel/simple_stats)
2
+
3
+
4
+ Install without Bundler:
5
+
6
+ gem install simple_stats --no-ri --no-rdoc
7
+
8
+ Install with Bundler:
9
+
10
+ ```ruby
11
+ gem "simple_stats"
12
+ ```
13
+
14
+ Then get some statistics on arrays or enumerables:
15
+
16
+ ```ruby
17
+ require 'rubygems' # if not using Bundler
18
+ require 'simple_stats'
19
+
20
+ samples = [3, 1, 0, 8, 2, 2, 3, 9]
21
+
22
+ samples.sum # 28
23
+ samples.mean # 3.5
24
+ samples.median # 2.5
25
+ samples.modes # [2, 3]
26
+ samples.frequencies
27
+ # {
28
+ # 0 => 1,
29
+ # 1 => 1,
30
+ # 2 => 2,
31
+ # 3 => 2,
32
+ # 8 => 1,
33
+ # 9 => 1
34
+ # }
35
+ samples.sorted_frequencies
36
+ # most common elements first
37
+ # [
38
+ # [2, 2],
39
+ # [3, 2],
40
+ # [0, 1],
41
+ # [1, 1],
42
+ # [8, 1],
43
+ # [9, 1]
44
+ # ]
45
+
46
+ # of course, you can take modes/frequencies on non-numeric data...
47
+ "banana nanny!".chars.modes
48
+ # ["n"]
49
+ "banana nanny!".chars.frequencies
50
+ # {
51
+ # " " => 1,
52
+ # "! "=> 1,
53
+ # "a" => 4,
54
+ # "b" => 1,
55
+ # "n" => 5,
56
+ # "y" => 1
57
+ # }
58
+ "banana nanny!".chars.sorted_frequencies
59
+ # [
60
+ # ["n", 5],
61
+ # ["a", 4],
62
+ # [" ", 1],
63
+ # ["!", 1],
64
+ # ["b", 1],
65
+ # ["y", 1]
66
+ # ]
67
+
68
+ # sum of nothing is 0
69
+ [].sum # 0
70
+
71
+ # mean and median of nothing is undefined
72
+ [].mean # nil
73
+ [].median # nil
74
+
75
+ # modes and frequencies return empty containers
76
+ [].modes # []
77
+ [].frequencies # {}
78
+ [].sorted_frequencies # []
79
+
80
+ # if elements are preset, mean and median always return floats
81
+ [1, 2, 3].mean # 2.0
82
+ [1, 2, 3].median # 2.0
83
+ [1, 2, 3, 4].mean # 2.5
84
+ [1, 2, 3, 4].median # 2.5
85
+
86
+ # sum, mode, and frequencies preserve the object class
87
+ [1, 2, 3].sum # 6
88
+ [1.0, 2.0, 3.0].sum # 6.0
89
+
90
+ # but no guarantees on class here:
91
+ [2.0, 2, 1].modes # [2]
92
+ [2, 2.0, 1].modes # [2.0]
93
+ ```
94
+
95
+ ## Help make it better!
96
+
97
+ Need something added? [Open an issue](https://github.com/brianhempel/simple_stats/issues). Or, even better, code it yourself and send a pull request:
98
+
99
+ # fork it on github, then clone:
100
+ git clone git@github.com:your_username/simple_stats.git
101
+ bundle install
102
+ rspec
103
+ # hack away
104
+ git push
105
+ # then make a pull request
106
+
107
+ ## License
108
+
109
+ Public domain. (I, Brian Hempel, the original author release this code to the public domain.)
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,66 @@
1
+ module Enumerable
2
+ def sum
3
+ inject(0) { |sum, x| sum + x }
4
+ end
5
+
6
+ def mean
7
+ count = self.count # count has to iterate if there's no size method
8
+ return nil if count == 0
9
+ sum / count.to_f
10
+ end
11
+
12
+ def median
13
+ sorted = sort
14
+ count = sorted.size
15
+ i = count / 2
16
+
17
+ return nil if count == 0
18
+ if count % 2 == 1
19
+ sorted[i].to_f
20
+ else
21
+ ( sorted[i-1] + sorted[i] ) / 2.0
22
+ end
23
+ end
24
+
25
+ def modes
26
+ sorted_frequencies = self.sorted_frequencies
27
+ sorted_frequencies.select do |item, frequency|
28
+ frequency == sorted_frequencies.first[1]
29
+ end.map do |item, frequency|
30
+ item
31
+ end
32
+ end
33
+
34
+ def frequencies
35
+ begin
36
+ sorted = sort
37
+ rescue NoMethodError # i.e. undefined method `<=>' for :my_symbol:Symbol
38
+ sorted = sort_by do |item|
39
+ item.respond_to?(:"<=>") ? item : item.to_s
40
+ end
41
+ end
42
+ current_item = nil;
43
+
44
+ Hash[
45
+ sorted.reduce([]) do |frequencies, item|
46
+ if frequencies.size == 0 || item != current_item
47
+ current_item = item
48
+ frequencies << [item, 1]
49
+ else
50
+ frequencies.last[1] += 1
51
+ frequencies
52
+ end
53
+ end
54
+ ]
55
+ end
56
+
57
+ def sorted_frequencies
58
+ frequencies.sort_by do |item, frequency|
59
+ if item.respond_to?(:"<=>")
60
+ [-frequency, item]
61
+ else
62
+ [-frequency, item.to_s]
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,3 @@
1
+ module SimpleStats
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,2 @@
1
+ require "simple_stats/version"
2
+ require "simple_stats/core_ext/enumerable"
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "simple_stats/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "simple_stats"
7
+ s.version = SimpleStats::VERSION
8
+ s.authors = ["Brian Hempel"]
9
+ s.email = ["plasticchicken@gmail.com"]
10
+ s.homepage = "https://github.com/brianhempel/simple_stats"
11
+ s.summary = "Simple mean, median, modes, sum, and frequencies for Ruby arrays and enumerables. Tested and sensible."
12
+ s.description = s.summary
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ # specify any dependencies here; for example:
20
+ # s.add_development_dependency "rspec"
21
+ # s.add_runtime_dependency "rest-client"
22
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ frequencies_expectations = {
4
+ [] => {},
5
+ [1] => { 1 => 1 },
6
+ [1.0] => { 1.0 => 1 },
7
+ [1, -1] => { -1 => 1, 1 => 1 },
8
+ [3, 1, 3] => { 3 => 2, 1 => 1 },
9
+ [3, 1, 3.0] => { 3 => 2, 1 => 1 },
10
+ [3.0, 1, 3] => { 3.0 => 2, 1 => 1 },
11
+ (0...0) => {},
12
+ (1..1) => { 1 => 1 },
13
+ (0..3) => { 0 => 1, 1 => 1, 2 => 1, 3 => 1 },
14
+ [BigDecimal("0.0")] => { BigDecimal("0.0") => 1 },
15
+ [-2, BigDecimal("1.0")] => { -2 => 1, BigDecimal("1.0") => 1 },
16
+ [:b, :c, :b, :c, :c, :a] => { :c => 3, :b => 2, :a => 1 }
17
+ }
18
+
19
+ describe Enumerable do
20
+ describe "#frequencies" do
21
+ frequencies_expectations.each do |data, expected|
22
+ it "is #{expected.inspect} for #{data.inspect}" do
23
+ frequencies = data.frequencies
24
+ frequencies.should == expected
25
+ frequencies.class.should == expected.class
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ mean_expectations = {
4
+ [] => nil,
5
+ [1] => 1.0,
6
+ [1.0] => 1.0,
7
+ [1, -1] => 0.0,
8
+ [1, 2, 3] => 2.0,
9
+ [1, 2, 3.0] => 2.0,
10
+ [2, 2, 3.0] => 7.0 / 3.0,
11
+ (0...0) => nil,
12
+ (1..1) => 1.0,
13
+ (0..3) => 1.5,
14
+ [BigDecimal("0.0")] => 0.0,
15
+ [-2, BigDecimal("1.0")] => -0.5
16
+ }
17
+
18
+ describe Enumerable do
19
+ describe "#mean" do
20
+ mean_expectations.each do |data, expected|
21
+ it "is #{expected.inspect} for #{data.inspect}" do
22
+ mean = data.mean
23
+ mean.should == expected
24
+ mean.class.should == expected.class
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ median_expectations = {
4
+ [] => nil,
5
+ [1] => 1.0,
6
+ [1.0] => 1.0,
7
+ [1, -1] => 0.0,
8
+ [1, 2, 3000] => 2.0,
9
+ [1, 2, 3000.0] => 2.0,
10
+ [2, 2, 3000.0] => 2.0,
11
+ (0...0) => nil,
12
+ (1..1) => 1.0,
13
+ (0..3) => 1.5,
14
+ [BigDecimal("0.0")] => 0.0,
15
+ [-2, BigDecimal("1.0")] => -0.5
16
+ }
17
+
18
+ describe Enumerable do
19
+ describe "#median" do
20
+ median_expectations.each do |data, expected|
21
+ it "is #{expected.inspect} for #{data.inspect}" do
22
+ median = data.median
23
+ median.should == expected
24
+ median.class.should == expected.class
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ modes_expectations = {
4
+ [] => [],
5
+ [1] => [1],
6
+ [1.0] => [1.0],
7
+ [1, -1] => [-1, 1],
8
+ [3, 1, 3] => [3],
9
+ [3, 1, 3.0] => [3],
10
+ [3.0, 1, 3] => [3.0],
11
+ (0...0) => [],
12
+ (1..1) => [1],
13
+ (0..3) => [0, 1, 2, 3],
14
+ [BigDecimal("0.0")] => [BigDecimal("0.0")],
15
+ [BigDecimal("1.0"), -2, BigDecimal("1.0")] => [BigDecimal("1.0")],
16
+ [:b, :c, :b, :c, :c, :a] => [:c]
17
+ }
18
+
19
+ describe Enumerable do
20
+ describe "#modes" do
21
+ modes_expectations.each do |data, expected|
22
+ it "is #{expected.inspect} for #{data.inspect}" do
23
+ modes = data.modes
24
+ modes.should == expected
25
+ modes.class.should == expected.class
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Enumerable do
4
+ describe "#sorted_frequencies" do
5
+ it "returns #frequencies sorted by [frequency, value]" do
6
+ enumerable = (0...0)
7
+ enumerable.stub(:frequencies) do
8
+ {
9
+ "White-breasted Nuthatch" => 1,
10
+ "Red-breasted Nuthatch" => 1,
11
+ "Brown Creeper" => 1,
12
+ "Squirrel" => 1,
13
+ "Marmelade" => 1000,
14
+ :yeah => 3,
15
+ :man => 3,
16
+ 11 => 12
17
+ }
18
+ end
19
+
20
+ enumerable.sorted_frequencies.should == [
21
+ ["Marmelade", 1000],
22
+ [11, 12],
23
+ [:man, 3],
24
+ [:yeah, 3],
25
+ ["Brown Creeper", 1],
26
+ ["Red-breasted Nuthatch", 1],
27
+ ["Squirrel", 1],
28
+ ["White-breasted Nuthatch", 1]
29
+ ]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ sum_expectations = {
4
+ [] => 0, # see http://en.wikipedia.org/wiki/Empty_sum
5
+ [1] => 1,
6
+ [1.0] => 1.0,
7
+ [1, -1] => 0,
8
+ [1, 2, 3] => 6,
9
+ [1, 2, 3.0] => 6.0,
10
+ (0...0) => 0, # see http://en.wikipedia.org/wiki/Empty_sum
11
+ (1..1) => 1,
12
+ (0..3) => 6,
13
+ [BigDecimal("0.0")] => BigDecimal("0.0"),
14
+ [3, BigDecimal("1.0")] => BigDecimal("4.0")
15
+ }
16
+
17
+ describe Enumerable do
18
+ describe "#sum" do
19
+ sum_expectations.each do |data, expected|
20
+ it "is #{expected.inspect} for #{data.inspect}" do
21
+ sum = data.sum
22
+ sum.should == expected
23
+ sum.class.should == expected.class
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
2
+ require 'simple_stats'
3
+ require 'bigdecimal'
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_stats
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Brian Hempel
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-02-10 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: Simple mean, median, modes, sum, and frequencies for Ruby arrays and enumerables. Tested and sensible.
22
+ email:
23
+ - plasticchicken@gmail.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - .gitignore
32
+ - .rspec
33
+ - .travis.yml
34
+ - Gemfile
35
+ - README.md
36
+ - Rakefile
37
+ - lib/simple_stats.rb
38
+ - lib/simple_stats/core_ext/enumerable.rb
39
+ - lib/simple_stats/version.rb
40
+ - simple_stats.gemspec
41
+ - spec/enumerable/frequencies_spec.rb
42
+ - spec/enumerable/mean_spec.rb
43
+ - spec/enumerable/median_spec.rb
44
+ - spec/enumerable/modes_spec.rb
45
+ - spec/enumerable/sorted_frequencies_spec.rb
46
+ - spec/enumerable/sum_spec.rb
47
+ - spec/spec_helper.rb
48
+ homepage: https://github.com/brianhempel/simple_stats
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options: []
53
+
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ requirements: []
75
+
76
+ rubyforge_project:
77
+ rubygems_version: 1.8.15
78
+ signing_key:
79
+ specification_version: 3
80
+ summary: Simple mean, median, modes, sum, and frequencies for Ruby arrays and enumerables. Tested and sensible.
81
+ test_files:
82
+ - spec/enumerable/frequencies_spec.rb
83
+ - spec/enumerable/mean_spec.rb
84
+ - spec/enumerable/median_spec.rb
85
+ - spec/enumerable/modes_spec.rb
86
+ - spec/enumerable/sorted_frequencies_spec.rb
87
+ - spec/enumerable/sum_spec.rb
88
+ - spec/spec_helper.rb