simple_stats 1.0.0

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/.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