# gleam_stats/stats

A module containing several helpful functions for computing and working with statistics.

• Types
• Statistical functions
• Miscellaneous functions

# Types

## Bin

</>

A type used to represent the bins in a histogram. The type is an alias of a tuple containing a min/max range and a count of the values in that range.

Example:
import gleeunit/should
import gleam/pair
import gleam_stats/math

pub fn example () {
// Create a bin
let bin: math.Bin = tuple(math.Range(0., 1.), 999)
// Retrieve min and max values
let math.Range(min, max) = pair.first(bin)
min
|> should.equal(0.)
max
|> should.equal(1.)
// Retrieve count
let count = pair.second(bin)
count
|> should.equal(999)
}
pub type Bin =
#(Range, Int)

## Range

</>

A type used to represent a min/max interval. The Range type is among others used to represent the bin boundaries in a histogram.

Example:
import gleam_stats/math
import gleeunit/should

pub fn example () {
// Create a range
let range = math.Range(0., 1.)
// Retrieve min and max values
let math.Range(min, max) = range
min
|> should.equal(0.)
max
|> should.equal(1.)
}
pub type Range {
Range(min: Float, max: Float)
}

### Constructors

• Range(min: Float, max: Float)

# Functions

## allclose

</>
pub fn allclose(xarr: List(Float), yarr: List(Float), rtol: Float, atol: Float) -> Result(
List(Bool),
Nil,
)

Determine if a list of values are close to or equivalent to a another list of reference values.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
let val: Float = 99.
let ref_val: Float = 100.
let xarr: List(Float) = list.repeat(val, 42)
let yarr: List(Float) = list.repeat(ref_val, 42)
// We set 'atol' and 'rtol' such that the values are equivalent
// if 'val' is within 1 percent of 'ref_val' +/- 0.1
let rtol: Float = 0.01
let atol: Float = 0.10
math.allclose(xarr, yarr, rtol, atol)
|> fn(zarr: Result(List(Bool), Nil)) -> Result(Bool, Nil) {
case zarr {
Ok(arr) ->
arr
|> list.all(fn(a: Bool) -> Bool { a })
|> Ok()
_ -> Error(Nil)
}
}
|> should.equal(Ok(True))
}

## amax

</>
pub fn amax(arr: List(Float)) -> Result(Float, Nil)

Returns the maximum value of a list.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.amax()
|> should.equal(Error(Nil))

[4., 4., 3., 2., 1.]
|> math.amax()
|> should.equal(Ok(4.))
}

## amin

</>
pub fn amin(arr: List(Float)) -> Result(Float, Nil)

Returns the minimum value of a list.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.amin()
|> should.equal(Error(Nil))

[4., 4., 3., 2., 1.]
|> math.amin()
|> should.equal(Ok(1.))
}

## argmax

</>
pub fn argmax(arr: List(Float)) -> Result(List(Int), Nil)

Returns the indices of the maximum values in a list.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.argmax()
|> should.equal(Error(Nil))

[4., 4., 3., 2., 1.]
|> math.argmax()
|> should.equal(Ok([0, 1]))
}

## argmin

</>
pub fn argmin(arr: List(Float)) -> Result(List(Int), Nil)

Returns the indices of the minimum values in a list.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.argmin()
|> should.equal(Error(Nil))

[4., 4., 3., 2., 1.]
|> math.argmin()
|> should.equal(Ok([4]))
}

## correlation

</>
pub fn correlation(xarr: List(Float), yarr: List(Float)) -> Result(
Float,
Nil,
)

Calculate the Pearson correlation coefficient to determine the linear relationship between the elements in two lists of equal length.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
math.correlation([], [])
|> should.equal(Error(Nil))

// Perfect positive correlation
let xarr0: List(Float) =
list.range(0, 100)
|> list.map(fn(x: Int) -> Float { int.to_float(x) })
let yarr0: List(Float) =
list.range(0, 100)
|> list.map(fn(x: Int) -> Float { int.to_float(x) })
math.correlation(xarr0, yarr0)
|> should.equal(Ok(1.))

// Perfect negative correlation
let xarr0: List(Float) =
list.range(0, 100)
|> list.map(fn(x: Int) -> Float { -1. *. int.to_float(x) })
let yarr0: List(Float) =
list.range(0, 100)
|> list.map(fn(x: Int) -> Float { int.to_float(x) })
math.correlation(xarr0, yarr0)
|> should.equal(Ok(-1.))
}

## freedman_diaconis_rule

</>
pub fn freedman_diaconis_rule(arr: List(Float)) -> Result(
Float,
Nil,
)

Use Freedman-Diaconis’s Rule to determine the bin widths of a histogram.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.freedman_diaconis_rule()
|> should.equal(Error(Nil))

// Calculate histogram bin widths
list.range(0, 1000)
|> list.map(fn(x: Int) -> Float { int.to_float(x) })
|> math.freedman_diaconis_rule()
|> should.equal(Ok(10.))
}

## gmean

</>
pub fn gmean(arr: List(Float)) -> Result(Float, Nil)

Calculcate the geometric mean of the elements in a list. Note that the geometric mean is only defined for positive numbers.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.gmean()
|> should.equal(Error(Nil))

[1., 3., 9.]
|> math.gmean()
|> should.equal(Ok(3.))
}

## histogram

</>
pub fn histogram(arr: List(Float), width: Float) -> Result(
List(#(Range, Int)),
Nil,
)

Create a histogram of the elements in a list.

Example:
import gleam_stats/math
import gleeunit/should

pub fn example () {
list.range(0, 100)
|> list.map(fn(x: Int) -> Float { int.to_float(x) })
// Below 25. is the bin width
// The Freedman-Diaconis’s Rule can be used to determine a decent value
|> math.histogram(25.)
|> should.equal(Ok([
tuple(math.Range(0., 25.), 25),
tuple(math.Range(25., 50.), 25),
tuple(math.Range(50., 75.), 25),
tuple(math.Range(75., 100.), 25),
]))

[]
|> math.histogram(1.)
|> should.equal(Error(Nil))
}

## hmean

</>
pub fn hmean(arr: List(Float)) -> Result(Float, Nil)

Calculcate the harmonic mean of the elements in a list. Note that the harmonic mean is only defined for positive numbers.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.hmean()
|> should.equal(Error(Nil))

[1., 3., 6.]
|> math.hmean()
|> should.equal(Ok(2.))
}

## iqr

</>
pub fn iqr(arr: List(Float)) -> Result(Float, Nil)

Calculate the interquartile range (IQR) of the elements in a list.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.iqr()
|> should.equal(Error(Nil))

[1., 2., 3., 4., 5.]
|> math.iqr()
|> should.equal(Ok(3.))
}

## isclose

</>
pub fn isclose(a: Float, b: Float, rtol: Float, atol: Float) -> Bool

Determine if a given value is close to or equivalent to a reference value based on supplied relative and absolute tolerance values. The equivalance of the two given values are then determined based on the equation:

absolute(a - b) <= (atol + rtol * absolute(b))
Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
let val: Float = 99.
let ref_val: Float = 100.
// We set 'atol' and 'rtol' such that the values are equivalent
// if 'val' is within 1 percent of 'ref_val' +/- 0.1
let rtol: Float = 0.01
let atol: Float = 0.10
math.isclose(val, ref_val, rtol, atol)
|> should.be_true()
}

## kurtosis

</>
pub fn kurtosis(arr: List(Float)) -> Result(Float, Nil)

Calculcate the sample kurtosis of a list of elements using the definition of Fisher.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.skewness()
|> should.equal(Error(Nil))

// No tail
// -> Fisher's definition gives kurtosis -3
[1., 1., 1., 1.]
|> math.kurtosis()
|> should.equal(Ok(-3.))

// Distribution with a tail
// -> Higher kurtosis
[1., 1., 1., 2.]
|> math.kurtosis()
|> fn(x: Result(Float, Nil)) -> Bool {
case x {
Ok(x) -> x >. -3.
}
}
|> should.be_true()
}

## mean

</>
pub fn mean(arr: List(Float)) -> Result(Float, Nil)

Calculcate the arithmetic mean of the elements in a list.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.mean()
|> should.equal(Error(Nil))

[1., 2., 3.]
|> math.mean()
|> should.equal(Ok(2.))
}

## median

</>
pub fn median(arr: List(Float)) -> Result(Float, Nil)

Calculcate the median of the elements in a list.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.median()
|> should.equal(Error(Nil))

[1., 2., 3.]
|> math.median()
|> should.equal(Ok(2.))

[1., 2., 3., 4.]
|> math.median()
|> should.equal(Ok(2.5))
}

## moment

</>
pub fn moment(arr: List(Float), n: Int) -> Result(Float, Nil)

Calculcate the n’th moment about the mean of a list of elements.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.moment(0)
|> should.equal(Error(Nil))

// 0th moment about the mean is 1. per definition
[0., 1., 2., 3., 4.]
|> math.moment(0)
|> should.equal(Ok(1.))

// 1st moment about the mean is 0. per definition
[0., 1., 2., 3., 4.]
|> math.moment(1)
|> should.equal(Ok(0.))

[0., 1., 2., 3., 4.]
|> math.moment(2)
|> should.equal(Ok(2.))
}

## percentile

</>
pub fn percentile(arr: List(Float), n: Int) -> Result(Float, Nil)

Calculate the n’th percentile of the elements in a list using linear interpolation between closest ranks.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.percentile(40)
|> should.equal(Error(Nil))

// Calculate 40th percentile
[15., 20., 35., 40., 50.]
|> math.percentile(40)
|> should.equal(Ok(29.))
}

## skewness

</>
pub fn skewness(arr: List(Float)) -> Result(Float, Nil)

Calculcate the sample skewness of a list of elements using the Fisher-Pearson coefficient of skewness.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.skewness()
|> should.equal(Error(Nil))

// No skewness
// -> Zero skewness
[1., 2., 3., 4.]
|> math.skewness()
|> should.equal(Ok(0.))

// Right-skewed distribution
// -> Positive skewness
[1., 1., 1., 2.]
|> math.skewness()
|> fn(x: Result(Float, Nil)) -> Bool {
case x {
Ok(x) -> x >. 0.
}
}
|> should.be_true()
}

## std

</>
pub fn std(arr: List(Float), ddof: Int) -> Result(Float, Nil)

Calculcate the sample standard deviation of the elements in a list.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
// Degrees of freedom
let ddof: Int = 1

[]
|> math.std(ddof)
|> should.equal(Error(Nil))

[1., 2., 3.]
|> math.std(ddof)
|> should.equal(Ok(1.))
}

## sum

</>
pub fn sum(arr: List(Float)) -> Float

Calculcate the sum of the elements in a list.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.sum()
|> should.equal(0.)

[1., 2., 3.]
|> math.sum()
|> should.equal(6.)
}

## trim

</>
pub fn trim(arr: List(Float), min: Int, max: Int) -> Result(
List(Float),
Nil,
)

Trim a list to a certain size given min/max indices. The min/max indices are inclusive.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
|> math.trim(0, 0)
|> should.equal(Error(Nil))

// Trim list to only middle part of list
[1., 2., 3., 4., 5., 6.]
|> math.trim(1, 4)
|> should.equal(Ok([2., 3., 4., 5.]))
}

## var

</>
pub fn var(arr: List(Float), ddof: Int) -> Result(Float, Nil)

Calculcate the sample variance of the elements in a list.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
// Degrees of freedom
let ddof: Int = 1

[]
|> math.var(ddof)
|> should.equal(Error(Nil))

[1., 2., 3.]
|> math.var(ddof)
|> should.equal(Ok(1.))
}

## zscore

</>
pub fn zscore(arr: List(Float), ddof: Int) -> Result(
List(Float),
Nil,
)

Calculate the z-score of each value in the list relative to the sample mean and standard deviation.

Example:
import gleeunit/should
import gleam_stats/math

pub fn example () {
[]
// Use degrees of freedom = 1
|> math.zscore(1)
|> should.equal(Error(Nil))

[1., 2., 3.]
// Use degrees of freedom = 1
|> math.zscore(1)
|> should.equal(Ok([-1., 0., 1.]))
}