Compare commits
17 Commits
Author | SHA1 | Date |
---|---|---|
Arthur Poulet | 924893d02d | |
Arthur POULET | 2c76ea54fc | |
Arthur POULET | 7c8a0e01ca | |
Arthur POULET | 0d9304d183 | |
Arthur POULET | 15aad6fd73 | |
Arthur POULET | 9739e3d42c | |
Arthur POULET | 7ba3ee31ee | |
Arthur POULET | 59fa29a95d | |
Arthur POULET | 2f0a0ad399 | |
Arthur POULET | e82eac24e1 | |
Arthur POULET | 6af7fa3a3e | |
Arthur POULET | 9a3b930177 | |
Arthur POULET | 4e9af8e8a3 | |
Arthur POULET | 5b1f28512e | |
Gunter Solf | e009c2943d | |
Arthur POULET | d2408b7c66 | |
Arthur POULET | da2d6566c1 |
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -1,30 +0,0 @@
|
|||
# v0.1.6
|
||||
- Improve factorial (handle BigInt)
|
||||
- Improve distributions (handle BigFloat and BigInt)
|
||||
- Define more specs
|
||||
- Improve Normale Distribution parameters (min-max instead of a-b)
|
||||
|
||||
# v0.1.5
|
||||
- add specs for every function
|
||||
- improve file architecture
|
||||
|
||||
# v0.1.4
|
||||
- fix binomial distribution
|
||||
|
||||
# v0.1.3
|
||||
- renamed crystal_proba to stats
|
||||
|
||||
# v0.1.2
|
||||
- renamed CrystalProba to crystal_proba
|
||||
|
||||
# v0.1.0
|
||||
|
||||
## Added
|
||||
- Initialization of the project
|
||||
- The Binomial Distribution and Normale Distribution are added
|
||||
- Basic specs are provided as documentation and unitary tests
|
||||
- License set to MIT
|
||||
- Compatibility with crystal v0.18
|
||||
|
||||
## Notes
|
||||
- Project inherited from RubyBinomial and RubyNormale, from myself
|
18
README.md
18
README.md
|
@ -1,7 +1,9 @@
|
|||
**Migrated to <https://git.sceptique.eu/Sceptique/stats>**
|
||||
|
||||
# stats
|
||||
|
||||
An expressive implementation of statistical distributions.
|
||||
Compatible with crystal v0.26.1
|
||||
Compatible with crystal v0.27.0.
|
||||
|
||||
## Installation
|
||||
|
||||
|
@ -10,7 +12,7 @@ Add this to your application's `shard.yml`:
|
|||
```yaml
|
||||
dependencies:
|
||||
stats:
|
||||
github: Nephos/stats
|
||||
git: https://git.sceptique.eu/Sceptique/stats
|
||||
```
|
||||
|
||||
|
||||
|
@ -92,10 +94,13 @@ Math.factorial(4) # => 24
|
|||
|
||||
### Quartiles & Boxplot
|
||||
|
||||
*Note: not big compatible yet*
|
||||
|
||||
```crystal
|
||||
[1, 3, 5].first_quartile # => 2.0 (alias of lower_quartile)
|
||||
[1, 3, 5].second_quartile # => 3.0 (alias of median)
|
||||
[1, 3, 5].third_quartile # => 4.0 (alias of upper_quartile)
|
||||
[1, 3, 5].quartiles # => [2.0, 3.0, 4.0] ([Q1, Q2, Q3])
|
||||
```
|
||||
|
||||
```crystal
|
||||
|
@ -117,9 +122,16 @@ arr.upper_fence(3) # => 47.5 (Q3 + 3 * IQR)
|
|||
arr.upper_outliers(3) # => [1337]
|
||||
```
|
||||
|
||||
### Frequency
|
||||
|
||||
```crystal
|
||||
[0, 1, 2, 3].frequency_of(0) # => 0.25 (amount of X in the population, by the size of the population)
|
||||
[0, 0, 1, 2, 3].all_frequencies # => { 0 => 0.4, 1 => 0.2, 2 => 0.2, 3 => 0.2}
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
- The lib is adapted to be usable with BigInt and BigFloat values
|
||||
- The lib should take care of "big" numbers
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: stats
|
||||
version: 0.2.3
|
||||
version: 0.3.0
|
||||
|
||||
authors:
|
||||
- Arthur Poulet <arthur.poulet@mailoo.org>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require "big"
|
||||
|
||||
describe Math::Correlation do
|
||||
it "test basic confidence interval" do
|
||||
arr1 = [1, 2, 2.5, 3, 3.5, 3.8, 4, 4.2, 4.4, 4.5]
|
||||
|
@ -9,4 +11,11 @@ describe Math::Correlation do
|
|||
arr1.covariance(arr2).round(4).should eq 4.2215
|
||||
arr1.correlation_coef(arr2).round(4).should eq 0.8906
|
||||
end
|
||||
|
||||
it "test big" do
|
||||
[BigInt.new(1), 2].correlation_coef([2, 3])
|
||||
[1, 2].correlation_coef([BigInt.new(2), 3])
|
||||
[BigInt.new(1), 2].correlation_coef([BigInt.new(2), 3])
|
||||
[1, 2].correlation_coef([BigInt.new(2), BigInt.new(3)])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,8 +10,8 @@ describe Math do
|
|||
Math.factorial(6).should eq 720
|
||||
end
|
||||
|
||||
it "factorial bigint" do
|
||||
res = (1..20).to_a.reduce(BigInt.new 1) { |e, i| e * BigInt.new(i) }
|
||||
Math.factorial(BigInt.new 20).should eq res
|
||||
it "factorial big" do
|
||||
res = (1..20).to_a.reduce(BigInt.new(1)) { |e, i| e * BigInt.new(i) }
|
||||
Math.factorial(BigInt.new(20)).should eq res
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
FREQ_LIMIT = 100
|
||||
|
||||
describe Math::Frequency do
|
||||
it "test trivia" do
|
||||
([] of Int32).frequency_of(0).should eq 0.0
|
||||
[0, 1, 2, 3].frequency_of(0).should eq 0.25
|
||||
[0, 0, 1, 2, 3].frequency_of(0).should eq 0.40
|
||||
[0, 0, 1, 2, 3].all_frequencies.should eq({0 => 0.4, 1 => 0.2, 2 => 0.2, 3 => 0.2})
|
||||
# allfreq1 = [0, 0, 1, 2, 3].all_frequencies(2)
|
||||
# allfreq1[1].should eq 0.4
|
||||
# allfreq1.size.should eq 2
|
||||
# expect_raises(Error) { [0, 0, 1, 2, 3].all_frequencies(2, true) }
|
||||
end
|
||||
|
||||
it "test basic" do
|
||||
FREQ_LIMIT.times do |modi|
|
||||
modulo = modi + 1
|
||||
# we should have the same or more because we don't / modulo in the freq
|
||||
arr = FREQ_LIMIT.times.to_a.map { |e| e % modulo }
|
||||
(arr.frequency_of(0) >= (1.0f64 / modulo)).should be_true
|
||||
|
||||
next if modulo <= 20
|
||||
# make an array with less or equal amount of iterations
|
||||
arr_less = FREQ_LIMIT.times.to_a.map { |e| e % (modulo + 5) }
|
||||
(arr.frequency_of(0) >= arr_less.frequency_of(0)).should be_true
|
||||
|
||||
# make an array with more or equal amount of iterations
|
||||
arr_more = FREQ_LIMIT.times.to_a.map { |e| e % (modulo - 5) }
|
||||
(arr.frequency_of(0) <= arr_more.frequency_of(0)).should be_true
|
||||
end
|
||||
|
||||
[0, 0, 0, 0, 1, 1, 1, 2, 2, 3].all_frequencies.should eq({0 => 0.4, 1 => 0.3, 2 => 0.2, 3 => 0.1})
|
||||
end
|
||||
end
|
|
@ -1,5 +1,11 @@
|
|||
require "big"
|
||||
|
||||
describe Math::MACD do
|
||||
it "test basic macd" do
|
||||
[1, 2, 3, 2, 1].macd(3).map { |e| e.round(3) }.should eq [2, 2.333, 2]
|
||||
end
|
||||
|
||||
it "test big basic macd" do
|
||||
puts [BigInt.new(1), BigInt.new(2), BigInt.new(3), BigInt.new(2), 1].macd(3).map { |e| e.round(3) }.should eq [2, 2.333, 2]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require "big"
|
||||
|
||||
describe Math::Mean do
|
||||
it "test several basic mean special case" do
|
||||
arr = ([] of Int32)
|
||||
|
@ -17,6 +19,11 @@ describe Math::Mean do
|
|||
[1, 2, -3].mean.should eq 0.0
|
||||
end
|
||||
|
||||
it "test mean on big" do
|
||||
[BigInt.new(1), 2, 3].mean.should eq 2.0
|
||||
[BigInt.new(1), BigInt.new(2), BigFloat.new(-3)].mean.should eq 0.0
|
||||
end
|
||||
|
||||
it "test quadratic mean" do
|
||||
[1, 2, 3, 2].quadratic_mean.round(4).should eq(2.1213)
|
||||
[1, 2, 1, 5, 10, 9, 1, -13, 2].quadratic_mean.round(4).should eq(6.549)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
require "big"
|
||||
|
||||
describe Math::Median do
|
||||
it "test trivia" do
|
||||
arr = ([]of Int32)
|
||||
arr = ([] of Int32)
|
||||
arr.median.should eq 0.0
|
||||
end
|
||||
|
||||
|
@ -10,7 +12,12 @@ describe Math::Median do
|
|||
|
||||
[1, 2, 5].median.should eq 2.0
|
||||
[2, 5, 1].median.should eq 2.0
|
||||
|
||||
|
||||
[4, 1, 1, 1, 2].median.should eq 1.0
|
||||
end
|
||||
|
||||
it "test big" do
|
||||
[BigInt.new(1.0), 2.0].median.should eq 1.5
|
||||
[BigInt.new(1.0), BigFloat.new(2.0)].median.should eq 1.5
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require "big"
|
||||
|
||||
module Math::Quartile
|
||||
it "trivial" do
|
||||
arr = [1, 3, 5]
|
||||
|
@ -5,15 +7,34 @@ module Math::Quartile
|
|||
arr.first_quartile.should eq 2.0
|
||||
arr.second_quartile.should eq 3.0
|
||||
arr.third_quartile.should eq 4.0
|
||||
|
||||
arr.quartiles.should eq [2.0, 3.0, 4.0]
|
||||
|
||||
arr.iqr.should eq 2.0
|
||||
end
|
||||
|
||||
# TODO
|
||||
# it "big" do
|
||||
# arr = [BigInt.new(1), BigFloat.new(3), 5]
|
||||
#
|
||||
# arr.first_quartile.should eq 2.0
|
||||
# arr.second_quartile.should eq 3.0
|
||||
# arr.third_quartile.should eq 4.0
|
||||
#
|
||||
# arr.quartiles.should eq [2.0, 3.0, 4.0]
|
||||
#
|
||||
# arr.iqr.should eq 2.0
|
||||
# end
|
||||
|
||||
it "odd size input" do
|
||||
arr = [6, 7, 15, 36, 39, 40, 41, 42, 43, 47, 49]
|
||||
|
||||
arr.first_quartile.should eq 25.5
|
||||
arr.second_quartile.should eq 40
|
||||
arr.third_quartile.should eq 42.5
|
||||
|
||||
arr.quartiles.should eq [25.5, 40, 42.5]
|
||||
|
||||
arr.iqr.should eq 17.0
|
||||
end
|
||||
|
||||
|
@ -23,6 +44,9 @@ module Math::Quartile
|
|||
arr.first_quartile.should eq 15.0
|
||||
arr.second_quartile.should eq 37.5
|
||||
arr.third_quartile.should eq 40.0
|
||||
|
||||
arr.quartiles.should eq [15, 37.5, 40]
|
||||
|
||||
arr.iqr.should eq 25.0
|
||||
end
|
||||
|
||||
|
@ -32,6 +56,9 @@ module Math::Quartile
|
|||
arr.first_quartile.should eq 31
|
||||
arr.second_quartile.should eq 87
|
||||
arr.third_quartile.should eq 119
|
||||
|
||||
arr.quartiles.should eq [31, 87, 119]
|
||||
|
||||
arr.iqr.should eq 88
|
||||
end
|
||||
|
||||
|
@ -42,6 +69,9 @@ module Math::Quartile
|
|||
arr.first_quartile.should eq 25.5
|
||||
arr.second_quartile.should eq 40
|
||||
arr.third_quartile.should eq 42.5
|
||||
|
||||
arr.quartiles.should eq [25.5, 40, 42.5]
|
||||
|
||||
arr.iqr.should eq 17
|
||||
end
|
||||
|
||||
|
@ -51,6 +81,9 @@ module Math::Quartile
|
|||
arr.first_quartile.should eq 3.5
|
||||
arr.second_quartile.should eq 6.5
|
||||
arr.third_quartile.should eq 14.5
|
||||
|
||||
arr.quartiles.should eq [3.5, 6.5, 14.5]
|
||||
|
||||
arr.iqr.should eq 11.0
|
||||
|
||||
arr.lower_fence.should eq -13.0
|
||||
|
|
|
@ -9,6 +9,16 @@ describe Math::StandardDeviation do
|
|||
arr.standard_deviation.should eq(standard_deviation)
|
||||
end
|
||||
|
||||
it "test big" do
|
||||
arr = [BigInt.new(1), BigFloat.new(2), 3, 4.0, 4]
|
||||
mean = (4 + 4 + 3 + 2 + 1) / 5.0
|
||||
variance = ((4 - mean)**2 + (4 - mean)**2 + (3 - mean)**2 + (2 - mean)**2 + (1 - mean)**2) / 5.0
|
||||
standard_deviation = Math.sqrt(variance)
|
||||
arr.mean.should eq(mean)
|
||||
arr.variance.should eq(variance)
|
||||
arr.standard_deviation.should eq(standard_deviation)
|
||||
end
|
||||
|
||||
it "test standard deviation without explanations" do
|
||||
arr = [1, 5, 23, 2, 0, 0, 1]
|
||||
arr.mean.round(2).should eq 4.57
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
module Math::Frequency(T)
|
||||
def frequency_of(value : T) : Float64
|
||||
return 0.0f64 if empty?
|
||||
count { |curr| curr == value }.to_f64 / size.to_f64
|
||||
end
|
||||
|
||||
def all_frequencies : Hash(T, Float64)
|
||||
values = to_set
|
||||
frequencies = Hash(T, Float64).new(0.0f64, values.size)
|
||||
each { |value| frequencies[value] += 1 }
|
||||
frequencies.each { |k, _| frequencies[k] = frequencies[k] / size }
|
||||
frequencies
|
||||
end
|
||||
end
|
||||
|
||||
module Enumerable(T)
|
||||
include Math::Frequency(T)
|
||||
end
|
|
@ -1,14 +1,14 @@
|
|||
module Math::Mean
|
||||
# Standard arithmetic mean
|
||||
# TODO: Handle big Float/Int
|
||||
def mean : Float64
|
||||
def mean
|
||||
return 0.0_f64 if empty?
|
||||
sum.to_f64 / size.to_f64
|
||||
end
|
||||
|
||||
# The root square mean of the list.
|
||||
# TODO: Handle big Float/Int
|
||||
def quadratic_mean : Float64
|
||||
def quadratic_mean
|
||||
return 0.0_f64 if empty?
|
||||
Math.sqrt map { |e| e ** 2 }.mean
|
||||
end
|
||||
|
@ -16,14 +16,14 @@ module Math::Mean
|
|||
# The geometric mean of the list.
|
||||
# For [a, b], a/c = c/b; c**2 = a*b
|
||||
# TODO: Handle big Float/Int
|
||||
def geometric_mean : Float64
|
||||
def geometric_mean
|
||||
return 0.0_f64 if empty?
|
||||
reduce { |l, r| l * r } ** (1.0 / size.to_f64)
|
||||
end
|
||||
|
||||
# The harmonic mean of the list.
|
||||
# TODO: Handle big Float/Int
|
||||
def harmonic_mean : Float64
|
||||
def harmonic_mean
|
||||
return 0.0_f64 if empty?
|
||||
size.to_f64 / map { |e| 1.0 / e }.sum
|
||||
end
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
module Math::Median
|
||||
def median : Float64
|
||||
def median
|
||||
return 0.0_f64 if empty?
|
||||
sorted = sort
|
||||
size = size()
|
||||
return sorted[(size - 1) / 2].to_f64 if size.odd?
|
||||
return sorted[(size - 1) / 2] / 1.0 if size.odd?
|
||||
(sorted[(size / 2) - 1] + sorted[size / 2]) / 2.0
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# There are several methods for computing the quartiles.
|
||||
#
|
||||
# There are several methods for computing the quartiles of an array.
|
||||
#
|
||||
# This library utilizes the method proposed by John Tukey
|
||||
# https://en.wikipedia.org/wiki/Quartile#Method_2
|
||||
#
|
||||
|
@ -28,10 +28,15 @@ module Math::Quartile
|
|||
upper_half.median
|
||||
end
|
||||
|
||||
# alias
|
||||
def third_quartile : Float64
|
||||
upper_quartile
|
||||
end
|
||||
|
||||
def quartiles : Array(Float64)
|
||||
[first_quartile, second_quartile, third_quartile]
|
||||
end
|
||||
|
||||
def iqr : Float64
|
||||
third_quartile - first_quartile
|
||||
end
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module Stats
|
||||
VERSION = "0.2"
|
||||
VERSION = "0.3"
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue