├── .gitignore ├── .travis.yml ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── certs └── jtescher.pem ├── checksum └── descriptive-statistics-2.2.0.gem.sha512 ├── descriptive-statistics.gemspec ├── lib ├── descriptive-statistics.rb └── descriptive-statistics │ ├── all-methods.rb │ ├── central-tendency.rb │ ├── dispersion.rb │ ├── shape.rb │ ├── spread.rb │ ├── stats.rb │ └── version.rb └── spec ├── lib ├── descriptive-statistics │ ├── all_methods_spec.rb │ ├── central_tendency_spec.rb │ ├── dispersion_spec.rb │ ├── shape_spec.rb │ ├── spread_spec.rb │ └── version_spec.rb └── descriptive_statistics_spec.rb └── spec_helper.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | .idea 7 | Gemfile.lock 8 | InstalledFiles 9 | _yardoc 10 | coverage 11 | doc/ 12 | lib/bundler/man 13 | pkg 14 | rdoc 15 | spec/reports 16 | test/tmp 17 | test/version_tmp 18 | tmp 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - jruby-head 4 | - jruby-9.1.9.0 5 | - rubinius-4.7 6 | - ruby-head 7 | - 2.7.0 8 | - 2.6.5 9 | - 2.5.7 10 | - 2.4.9 11 | 12 | matrix: 13 | allow_failures: 14 | - rvm: jruby-head 15 | - rvm: rubinius-4.7 16 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in descriptive-statistics.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Julian Tescher 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DescriptiveStatistics 2 | 3 | This gem calculates descriptive statistics including measures of central tendency (e.g. mean, median mode), dispersion 4 | (e.g. range, and quartiles), and spread (e.g variance and standard deviation). 5 | 6 | Tested against 2.4.9, 2.5.7, 2.6.5, 2.7.0, ruby-head, jruby-9.1.9.0, jruby-head and rubinius-4.7. 7 | 8 | [![Build Status](https://secure.travis-ci.org/jtescher/descriptive-statistics.png)](http://travis-ci.org/jtescher/descriptive-statistics) 9 | [![Dependency Status](https://gemnasium.com/jtescher/descriptive-statistics.png)](https://gemnasium.com/jtescher/descriptive-statistics) 10 | [![Code Climate](https://codeclimate.com/github/jtescher/descriptive-statistics.png)](https://codeclimate.com/github/jtescher/descriptive-statistics) 11 | [![Gem Version](https://badge.fury.io/rb/descriptive-statistics.png)](http://badge.fury.io/rb/descriptive-statistics) 12 | [![Coverage Status](https://coveralls.io/repos/jtescher/descriptive-statistics/badge.png)](https://coveralls.io/r/jtescher/descriptive-statistics) 13 | 14 | ## Installation 15 | 16 | Add this line to your application's Gemfile: 17 | 18 | gem 'descriptive-statistics' 19 | 20 | And then execute: 21 | 22 | $ bundle 23 | 24 | Or install it yourself as: 25 | 26 | $ gem install descriptive-statistics 27 | 28 | ## Usage 29 | 30 | ### Central Tendency: 31 | ```ruby 32 | stats = DescriptiveStatistics::Stats.new([1,1,2,3,10]) 33 | stats.mean #=> 3.4 34 | stats.median #=> 2 35 | stats.mode #=> 1 36 | ``` 37 | 38 | ### Dispersion: 39 | ```ruby 40 | stats = DescriptiveStatistics::Stats.new([1,1,2,3,10]) 41 | stats.range #=> 9 42 | stats.min #=> 1 43 | stats.max #=> 10 44 | stats.percentile_from_value(10) #=> 80 45 | stats.value_from_percentile(60) #=> 3 46 | ``` 47 | 48 | ### Spread: 49 | ```ruby 50 | stats = DescriptiveStatistics::Stats.new([1,1,2,3,10]) 51 | stats.variance #=> 14.299999999999999 52 | stats.population_variance #=> 11.44 53 | stats.standard_deviation #=> 3.7815340802378072 54 | stats.relative_standard_deviation #=> 99.47961485463391 55 | ``` 56 | 57 | ### Other Measures: 58 | ```ruby 59 | stats = DescriptiveStatistics::Stats.new([1,1,2,3,10]) 60 | stats.skewness #=> 1.188328915820243 61 | stats.kurtosis #=> 2.405613966453127 62 | ``` 63 | 64 | ## Alternative Usage (Not suggested) 65 | If you want to monkey patch descriptive statistics methods into Enumerable, you can use the following: 66 | 67 | (e.g. config/initializers/descriptive_statistics_monkey_patch.rb) 68 | ```ruby 69 | require 'descriptive-statistics' 70 | 71 | module Enumerable 72 | include DescriptiveStatistics 73 | 74 | # Warning: hacky evil meta programming. Required because classes that have already included 75 | # Enumerable will not otherwise inherit the statistics methods. 76 | DescriptiveStatistics.instance_methods.each do |m| 77 | define_method(m, DescriptiveStatistics.instance_method(m)) 78 | end 79 | end 80 | ``` 81 | 82 | Then you can use these methods directly on Arrays: 83 | ```ruby 84 | [1,1,2,3,10].mean #=> 3.4 85 | ``` 86 | 87 | ## Contributing 88 | 89 | 1. Fork it 90 | 2. Create your feature branch (`git checkout -b my-new-feature`) 91 | 3. Commit your changes (`git commit -am 'Add some feature'`) 92 | 4. Push to the branch (`git push origin my-new-feature`) 93 | 5. Create new Pull Request 94 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require 'rspec/core/rake_task' 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec -------------------------------------------------------------------------------- /certs/jtescher.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDdDCCAlygAwIBAgIBATANBgkqhkiG9w0BAQUFADBAMRIwEAYDVQQDDAlqYXRl 3 | c2NoZXIxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv 4 | bTAeFw0xNjA5MjYxNzU4NTRaFw0xNzA5MjYxNzU4NTRaMEAxEjAQBgNVBAMMCWph 5 | dGVzY2hlcjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYD 6 | Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7ptCQvN739Rjos4e 7 | G2Y8uGCQxpBoXozU36PXLtR5ws7aly1QV0zRc1cy7nKnOSnXn7dEfbLGZS6/87pM 8 | rDFFszHsn/dizlXe3wejHePyG1EsYnIezISP9YSDcm7qpysrUAa2fKPqqZ6DNbIP 9 | 6wRF9Cun4hvmQPDrs0zKU6p43XHnJUg7YBYCOVACa7eFD1EOya+599hFMhnWChvT 10 | rKkVc/JRvmKYLIkB6Y6N3TFrVi9x0Qpo4fjG5rQ9xxNZhpFIOMJ0VJbuRSIMlLwr 11 | Ryd/QG0BcvkSHph/ZDlgfZ1V/lzWWq+mZOt/U+t6cVITSET5XDzHkeZ0BodGyAMr 12 | lZpggQIDAQABo3kwdzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU 13 | QLcGxzEu2F2XI+3tIWSu8KqAFrkwHgYDVR0RBBcwFYETamF0ZXNjaGVyQGdtYWls 14 | LmNvbTAeBgNVHRIEFzAVgRNqYXRlc2NoZXJAZ21haWwuY29tMA0GCSqGSIb3DQEB 15 | BQUAA4IBAQCh9hDqN3lZw0PLVkXVcnwnl3KAjJfwCwk1okeuJ+IeQSfRLPp2ECLn 16 | j87oXZPcBukPB0/zTHcF/eBPIGvOedqVhp9SEar51dXLdiCe+deXx/bI3YMRdTGH 17 | 6NtqR6hWjm+hzBthxDsKhmQRczJ+5FNzAoW+pzf7ouKGfeFiFPwvAMolzsi2T+O/ 18 | AmsZcBYVI8HbrnuoQI30XfdhNoRrKhoMyzAyVdWX9xQW56TWUO+o8iXBKjOxX2C5 19 | 8lVFrLvGNGPCLQmEf498hBYT99EVYiuiI0F7YlTmBdzL1uwTMk5le/b0NguYdSJ7 20 | qKlUP9usSwMVc+qmaOg1EYfPGYvt63qS 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /checksum/descriptive-statistics-2.2.0.gem.sha512: -------------------------------------------------------------------------------- 1 | 769e23db80b5cae7585703daccf1b9286d46e28b2409f61f932232280d610086c408a555d66dbcaf9f799bb2094dfd945a40df8442e5af90b0a49610ca9634aa -------------------------------------------------------------------------------- /descriptive-statistics.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'descriptive-statistics/version' 5 | 6 | Gem::Specification.new do |gem| 7 | gem.name = "descriptive-statistics" 8 | gem.version = DescriptiveStatistics::VERSION 9 | gem.authors = ["Julian Tescher"] 10 | gem.email = ["virulent@gmail.com"] 11 | gem.description = %q{Descriptive Statistics Calculator} 12 | gem.summary = %q{Simply calculate descriptive statistics such as measures of central tendency (e.g. mean,median, 13 | mode), dispersion (e.g. range and quartiles), and spread (e.g variance and standard deviation)} 14 | gem.homepage = "https://github.com/jtescher/descriptive-statistics" 15 | gem.signing_key = File.expand_path('~/.ssh/gem-private_key.pem') if $0 =~ /gem\z/ 16 | gem.cert_chain = ['certs/jtescher.pem'] 17 | gem.license = "MIT" 18 | 19 | gem.files = `git ls-files`.split($/) 20 | gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } 21 | gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) 22 | gem.require_paths = ["lib"] 23 | 24 | gem.add_development_dependency "rspec", "~> 2.14" 25 | gem.add_development_dependency "rake", "~> 10.1" 26 | if RUBY_VERSION > "1.9" 27 | gem.add_development_dependency "simplecov", "~> 0.14" 28 | gem.add_development_dependency "coveralls", "~> 0.8" 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/descriptive-statistics.rb: -------------------------------------------------------------------------------- 1 | require "descriptive-statistics/version" 2 | require "descriptive-statistics/all-methods" 3 | require "descriptive-statistics/stats" 4 | 5 | module DescriptiveStatistics 6 | include AllMethods 7 | end -------------------------------------------------------------------------------- /lib/descriptive-statistics/all-methods.rb: -------------------------------------------------------------------------------- 1 | require 'descriptive-statistics/central-tendency' 2 | require 'descriptive-statistics/dispersion' 3 | require 'descriptive-statistics/spread' 4 | require 'descriptive-statistics/shape' 5 | 6 | module DescriptiveStatistics 7 | module AllMethods 8 | include CentralTendency 9 | include Dispersion 10 | include Shape 11 | include Spread 12 | end 13 | end -------------------------------------------------------------------------------- /lib/descriptive-statistics/central-tendency.rb: -------------------------------------------------------------------------------- 1 | module DescriptiveStatistics 2 | module CentralTendency 3 | def sum(identity = 0, &block) 4 | if block_given? 5 | DescriptiveStatistics::Stats.new(map(&block)).sum(identity) 6 | else 7 | inject(:+) || identity 8 | end 9 | end 10 | 11 | def mean 12 | return if length < 1 13 | sum / length.to_f 14 | end 15 | 16 | def median 17 | return if length < 1 18 | sorted = self.sort 19 | 20 | if length % 2 == 0 21 | (sorted[(length/2) -1 ] + sorted[length / 2]) / 2.0 22 | else 23 | sorted[length / 2] 24 | end 25 | end 26 | 27 | def mode 28 | return if length < 1 29 | frequency_distribution = inject(Hash.new(0)) { |hash, value| hash[value] += 1; hash } 30 | top_2 = frequency_distribution.sort { |a,b| b[1] <=> a[1] } .take(2) 31 | if top_2.length == 1 32 | top_2.first.first # Only one value in distribution, so it's the mode. 33 | elsif top_2.first.last == top_2.last.last 34 | nil # Equal frequency, no mode. 35 | else 36 | top_2.first.first # Most frequent is mode. 37 | end 38 | end 39 | end 40 | end -------------------------------------------------------------------------------- /lib/descriptive-statistics/dispersion.rb: -------------------------------------------------------------------------------- 1 | module DescriptiveStatistics 2 | module Dispersion 3 | def range 4 | return if length < 1 5 | sorted = sort 6 | sorted.last - sorted.first 7 | end 8 | 9 | def percentile_from_value(value) 10 | return if length < 1 11 | (sort.index(value) / length.to_f * 100).ceil 12 | end 13 | 14 | def value_from_percentile(percentile) 15 | return if length < 1 16 | value_index = (percentile.to_f / 100 * length).ceil 17 | sort[value_index] 18 | end 19 | end 20 | end -------------------------------------------------------------------------------- /lib/descriptive-statistics/shape.rb: -------------------------------------------------------------------------------- 1 | module DescriptiveStatistics 2 | module Shape 3 | 4 | def skewness 5 | return if length == 0 6 | return 0 if length == 1 7 | sum_cubed_deviation / ((length - 1) * cubed_standard_deviation.to_f) 8 | end 9 | 10 | def kurtosis 11 | return if length == 0 12 | return 0 if length == 1 13 | sum_quarted_deviation / ((length - 1) * quarted_standard_deviation.to_f) 14 | end 15 | 16 | private 17 | 18 | def sum_cubed_deviation 19 | precalculated_mean = mean 20 | inject(0) {|sum, value| sum + (value - precalculated_mean) ** 3} 21 | end 22 | 23 | def cubed_standard_deviation 24 | standard_deviation ** 3 25 | end 26 | 27 | def sum_quarted_deviation 28 | precalculated_mean = mean 29 | inject(0) {|sum, value| sum + (value - precalculated_mean) ** 4} 30 | end 31 | 32 | def quarted_standard_deviation 33 | standard_deviation ** 4 34 | end 35 | 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/descriptive-statistics/spread.rb: -------------------------------------------------------------------------------- 1 | module DescriptiveStatistics 2 | module Spread 3 | def variance 4 | return if length < 1 5 | precalculated_mean = mean 6 | sum = self.inject(0) {|accumulator, value| accumulator + (value - precalculated_mean) ** 2 } 7 | sum / (length.to_f - 1) 8 | end 9 | 10 | def population_variance 11 | return if length < 1 12 | precalculated_mean = mean 13 | sum = self.inject(0) {|accumulator, value| accumulator + (value - precalculated_mean) ** 2 } 14 | sum / length.to_f 15 | end 16 | 17 | def standard_deviation 18 | return if length < 2 19 | Math.sqrt(variance) 20 | end 21 | 22 | def relative_standard_deviation 23 | return if length < 1 24 | precalculated_mean = mean 25 | (population_standard_deviation / precalculated_mean) * 100.0 26 | end 27 | 28 | def population_standard_deviation 29 | return if length < 1 30 | Math.sqrt(population_variance) 31 | end 32 | 33 | def zscore 34 | return if length < 2 35 | stdev = standard_deviation 36 | m = mean 37 | stdev.zero? ? Array.new(self.length, 0) : self.collect { |v| (v - m) / stdev } 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/descriptive-statistics/stats.rb: -------------------------------------------------------------------------------- 1 | require 'delegate' 2 | require "descriptive-statistics/all-methods" 3 | 4 | module DescriptiveStatistics 5 | class Stats < SimpleDelegator 6 | include AllMethods 7 | end 8 | end -------------------------------------------------------------------------------- /lib/descriptive-statistics/version.rb: -------------------------------------------------------------------------------- 1 | module DescriptiveStatistics 2 | VERSION = "2.2.0" 3 | end 4 | -------------------------------------------------------------------------------- /spec/lib/descriptive-statistics/all_methods_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DescriptiveStatistics::AllMethods do 4 | it 'should include all stats modules' do 5 | DescriptiveStatistics::AllMethods.ancestors.should == [ 6 | DescriptiveStatistics::AllMethods, 7 | DescriptiveStatistics::Spread, 8 | DescriptiveStatistics::Shape, 9 | DescriptiveStatistics::Dispersion, 10 | DescriptiveStatistics::CentralTendency 11 | ] 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/lib/descriptive-statistics/central_tendency_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DescriptiveStatistics::CentralTendency do 4 | describe '#sum' do 5 | it 'returns the amount attained by adding all numbers in the array' do 6 | DescriptiveStatistics::Stats.new([1,2,6]).sum.should == 9 7 | end 8 | 9 | it 'allows a block to be passed' do 10 | DescriptiveStatistics::Stats.new([1,2,6]).sum{ |x| x * 2 }.should == 18 11 | end 12 | 13 | it 'returns 0 if empty' do 14 | DescriptiveStatistics::Stats.new([]).sum.should == 0 15 | end 16 | end 17 | 18 | describe '#mean' do 19 | it 'returns the sum of the values over the count of the values' do 20 | DescriptiveStatistics::Stats.new([1,2,6]).mean.should == 3 21 | end 22 | 23 | it 'returns nil if empty' do 24 | DescriptiveStatistics::Stats.new([]).mean.should be_nil 25 | end 26 | end 27 | 28 | describe '#median' do 29 | it 'returns the value lying at the midpoint of the array' do 30 | DescriptiveStatistics::Stats.new([1,2,6]).median.should == 2 31 | end 32 | 33 | it 'returns the mean of the two midpoint values if the array length is even' do 34 | DescriptiveStatistics::Stats.new([1,2,3,6]).median.should == 2.5 35 | end 36 | 37 | it 'returns nil if empty' do 38 | DescriptiveStatistics::Stats.new([]).median.should be_nil 39 | end 40 | end 41 | 42 | describe '#mode' do 43 | it 'returns the most frequent value' do 44 | DescriptiveStatistics::Stats.new([1,1,2,46]).mode.should == 1 45 | end 46 | 47 | it 'returns nil if there is no most frequent value' do 48 | DescriptiveStatistics::Stats.new([1,2,3]).mode.should be_nil 49 | end 50 | 51 | it 'returns the first value if there is only one' do 52 | DescriptiveStatistics::Stats.new([3.5]).mode.should == 3.5 53 | end 54 | 55 | it 'returns nil if empty' do 56 | DescriptiveStatistics::Stats.new([]).mode.should be_nil 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /spec/lib/descriptive-statistics/dispersion_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DescriptiveStatistics::Dispersion do 4 | describe '#range' do 5 | it 'returns the mean squared deviation of the sample (n - 1 denominator)' do 6 | DescriptiveStatistics::Stats.new([1,2,6]).range.should == 5 7 | end 8 | 9 | it 'returns nil if empty' do 10 | DescriptiveStatistics::Stats.new([]).range.should be_nil 11 | end 12 | end 13 | 14 | describe '#min' do 15 | it 'delegates to array' do 16 | DescriptiveStatistics::Stats.new([1,2,6]).min.should == 1 17 | end 18 | 19 | it 'returns nil if empty' do 20 | DescriptiveStatistics::Stats.new([]).min.should be_nil 21 | end 22 | end 23 | 24 | describe '#max' do 25 | it 'delegates to array' do 26 | DescriptiveStatistics::Stats.new([1,2,6]).max.should == 6 27 | end 28 | 29 | it 'returns nil if empty' do 30 | DescriptiveStatistics::Stats.new([]).max.should be_nil 31 | end 32 | end 33 | 34 | describe '#percentile_from_value' do 35 | it 'returns the precise percentile of each value' do 36 | data = [95.1772, 95.1567, 95.1937, 95.1959, 95.1442, 95.061, 95.1591, 95.1195,95.1065, 95.0925, 95.199, 95.1682] 37 | percentiles = [0,9,17,25,34,42,50,59,67,75,84,92] 38 | stats = DescriptiveStatistics::Stats.new(data) 39 | data.sort.each_with_index do |datum, i| 40 | stats.percentile_from_value(datum).should == percentiles[i] 41 | end 42 | end 43 | 44 | it 'returns nil if empty' do 45 | DescriptiveStatistics::Stats.new([]).percentile_from_value(1).should be_nil 46 | end 47 | end 48 | 49 | describe '#value_from_percentile' do 50 | it 'returns the precise percentile of each value' do 51 | data = [95.1772, 95.1567, 95.1937, 95.1959, 95.1442, 95.061, 95.1591, 95.1195,95.1065, 95.0925, 95.199, 95.1682] 52 | percentiles = [0,10,20,30,40,50,60,70,80,90] 53 | values = [95.061,95.1065,95.1195,95.1442,95.1567,95.1591,95.1772,95.1937,95.1959,95.199] 54 | stats = DescriptiveStatistics::Stats.new(data) 55 | percentiles.sort.each_with_index do |percentile, i| 56 | stats.value_from_percentile(percentile).should == values[i] 57 | end 58 | end 59 | 60 | it 'returns nil if empty' do 61 | DescriptiveStatistics::Stats.new([]).value_from_percentile(1).should be_nil 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /spec/lib/descriptive-statistics/shape_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DescriptiveStatistics::Shape do 4 | describe '#skewness' do 5 | it 'returns the measure of skewness of the data as close to 0 when not skewed' do 6 | DescriptiveStatistics::Stats.new([1,3,5,3,1]).skewness.should == 0.30734449954312965 7 | end 8 | 9 | it 'returns the measure of skewness of the data as high when skewed' do 10 | DescriptiveStatistics::Stats.new([50,10,1,1,1]).skewness.should == 1.2374536958450908 11 | end 12 | 13 | it 'returns 0 if only one element' do 14 | DescriptiveStatistics::Stats.new([1]).skewness.should == 0 15 | end 16 | 17 | it 'returns nil if empty' do 18 | DescriptiveStatistics::Stats.new([]).skewness.should be_nil 19 | end 20 | end 21 | 22 | describe '#kurtosis' do 23 | it 'returns the measure of kurtosis of the data as close to 0 when not skewed' do 24 | DescriptiveStatistics::Stats.new([1,3,5,3,1]).kurtosis.should == 1.477551020408163 25 | end 26 | 27 | it 'returns the measure of skewness of the data as high when skewed' do 28 | DescriptiveStatistics::Stats.new([99,10,1,1,1]).kurtosis.should == 2.56586117539186 29 | end 30 | 31 | it 'returns 0 if only one element' do 32 | DescriptiveStatistics::Stats.new([1]).kurtosis.should == 0 33 | end 34 | 35 | it 'returns nil if empty' do 36 | DescriptiveStatistics::Stats.new([]).kurtosis.should be_nil 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /spec/lib/descriptive-statistics/spread_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DescriptiveStatistics::Spread do 4 | describe '#variance' do 5 | it 'returns the mean squared deviation of the sample (n - 1 denominator)' do 6 | DescriptiveStatistics::Stats.new([1,2,6]).variance.should == 7 7 | end 8 | 9 | it 'returns nil if empty' do 10 | DescriptiveStatistics::Stats.new([]).variance.should be_nil 11 | end 12 | end 13 | 14 | describe '#population_variance' do 15 | it 'returns the mean squared deviation of the sample' do 16 | DescriptiveStatistics::Stats.new([1,2,3,4]).population_variance.should == 1.25 17 | end 18 | 19 | it 'returns nil if empty' do 20 | DescriptiveStatistics::Stats.new([]).population_variance.should be_nil 21 | end 22 | end 23 | 24 | describe '#standard_deviation' do 25 | it 'returns the square root of the variance' do 26 | DescriptiveStatistics::Stats.new([1,2,6]).standard_deviation.should == 2.6457513110645907 27 | end 28 | 29 | it 'returns nil for single element arrays' do 30 | DescriptiveStatistics::Stats.new([1]).standard_deviation.should be_nil 31 | end 32 | 33 | it 'returns nil if empty' do 34 | DescriptiveStatistics::Stats.new([]).standard_deviation.should be_nil 35 | end 36 | end 37 | 38 | describe '#relative_standard_deviation' do 39 | it 'returns 0 for constant values' do 40 | DescriptiveStatistics::Stats.new([100, 100, 100]).relative_standard_deviation.should == 0 41 | end 42 | 43 | it 'returns the population_standard_deviation divided by the mean * 100' do 44 | DescriptiveStatistics::Stats.new([90, 100, 110]).relative_standard_deviation.should be_within(0.01).of(8.16) 45 | DescriptiveStatistics::Stats.new([1, 5, 6, 8, 10, 40, 65, 88]).relative_standard_deviation.should be_within(0.01).of(110.41) 46 | end 47 | 48 | it 'returns nil if empty' do 49 | DescriptiveStatistics::Stats.new([]).relative_standard_deviation.should be_nil 50 | end 51 | end 52 | 53 | describe '#population_standard_deviation' do 54 | it 'returns the square root of the population_variance' do 55 | DescriptiveStatistics::Stats.new([1,2,6]).population_standard_deviation.should == 2.160246899469287 56 | end 57 | 58 | it 'returns 0 for single element arrays' do 59 | DescriptiveStatistics::Stats.new([1]).population_standard_deviation.should == 0 60 | end 61 | 62 | it 'returns nil if empty' do 63 | DescriptiveStatistics::Stats.new([]).population_standard_deviation.should be_nil 64 | end 65 | end 66 | 67 | describe '#zscore' do 68 | it 'returns the zscore for the sample' do 69 | DescriptiveStatistics::Stats.new([1, 2, 3]).zscore.should == [-1.0, 0.0, 1.0] 70 | end 71 | 72 | it 'returns nil for single element arrays' do 73 | DescriptiveStatistics::Stats.new([1]).zscore.should be_nil 74 | end 75 | 76 | it 'returns nil if empty' do 77 | DescriptiveStatistics::Stats.new([]).zscore.should be_nil 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /spec/lib/descriptive-statistics/version_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DescriptiveStatistics do 4 | it "should have a VERSION constant" do 5 | subject.const_get('VERSION').should_not be_empty 6 | end 7 | end -------------------------------------------------------------------------------- /spec/lib/descriptive_statistics_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe DescriptiveStatistics do 4 | it 'should allow hacky monkey patches to add methods to structures like arrays' do 5 | if RUBY_VERSION == '1.9.3' and RUBY_ENGINE == 'ruby' # Ignore older versions of ruby and Rubinius 6 | module Enumerable 7 | include DescriptiveStatistics::AllMethods 8 | 9 | # Warning: hacky evil meta programming. Required to have classes that include array get the methods too. 10 | DescriptiveStatistics.instance_methods.each do |m| 11 | define_method(m, DescriptiveStatistics::AllMethods.instance_method(m)) 12 | end 13 | end 14 | 15 | [1,2,3].mean.should == 2 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | begin 2 | require 'simplecov' 3 | require 'coveralls' 4 | #SimpleCov.formatter = Coveralls::SimpleCov::Formatter 5 | SimpleCov.start 6 | rescue LoadError 7 | # Simplecov and coveralls do not work in Ruby < 1.9 8 | end 9 | 10 | 11 | $LOAD_PATH << File.expand_path('../../lib', __FILE__) 12 | require 'descriptive-statistics' --------------------------------------------------------------------------------