diff --git a/go.mod b/go.mod
index a31517f..f3dead4 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
github.com/alecthomas/kingpin/v2 v2.4.0
github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973
github.com/kubeservice-stack/common v1.9.1
- github.com/montanaflynn/stats v0.9.0
+ github.com/montanaflynn/stats v0.11.0
github.com/prometheus/client_golang v1.23.2
github.com/prometheus/common v0.69.0
github.com/prometheus/exporter-toolkit v0.16.0
diff --git a/go.sum b/go.sum
index 0172567..1b5a35f 100644
--- a/go.sum
+++ b/go.sum
@@ -45,8 +45,8 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
-github.com/montanaflynn/stats v0.9.0 h1:tsBJ0RXwph9BmAuFoCmqGv6e8xa0MENQ8m0ptKq29mQ=
-github.com/montanaflynn/stats v0.9.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
+github.com/montanaflynn/stats v0.11.0 h1:zDghK0ZIhSGNLdZaZYob15c5fjgVnuTzv/MRZ9UJifY=
+github.com/montanaflynn/stats v0.11.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
diff --git a/vendor/github.com/montanaflynn/stats/.github-write-test b/vendor/github.com/montanaflynn/stats/.github-write-test
deleted file mode 100644
index 30d74d2..0000000
--- a/vendor/github.com/montanaflynn/stats/.github-write-test
+++ /dev/null
@@ -1 +0,0 @@
-test
\ No newline at end of file
diff --git a/vendor/github.com/montanaflynn/stats/.gitignore b/vendor/github.com/montanaflynn/stats/.gitignore
index 75a2a3a..ba3574a 100644
--- a/vendor/github.com/montanaflynn/stats/.gitignore
+++ b/vendor/github.com/montanaflynn/stats/.gitignore
@@ -2,6 +2,5 @@ coverage.out
coverage.txt
release-notes.txt
.directory
-.chglog
.vscode
.DS_Store
\ No newline at end of file
diff --git a/vendor/github.com/montanaflynn/stats/CHANGELOG.md b/vendor/github.com/montanaflynn/stats/CHANGELOG.md
index 580ce3e..4a82f6d 100644
--- a/vendor/github.com/montanaflynn/stats/CHANGELOG.md
+++ b/vendor/github.com/montanaflynn/stats/CHANGELOG.md
@@ -2,6 +2,77 @@
## [Unreleased]
+
+
+
+## [v0.11.0] - 2026-07-13
+### Add
+- Add Interp for piecewise-linear interpolation ([#121](https://github.com/montanaflynn/stats/issues/121))
+- Add Histogram with equal-width bins ([#120](https://github.com/montanaflynn/stats/issues/120))
+- Add KendallTau rank correlation coefficient ([#119](https://github.com/montanaflynn/stats/issues/119))
+- Add SEM, RMS, Product, and PercentileOfScore ([#118](https://github.com/montanaflynn/stats/issues/118))
+- Add MovingMedian, MovingMin, MovingMax, MovingSum, and EWMA ([#117](https://github.com/montanaflynn/stats/issues/117))
+- Add TrimmedMean and Winsorize robust statistics ([#116](https://github.com/montanaflynn/stats/issues/116))
+- Add Kurtosis, PopulationKurtosis, and SampleKurtosis ([#115](https://github.com/montanaflynn/stats/issues/115))
+- Add Clip and Rescale elementwise transforms ([#114](https://github.com/montanaflynn/stats/issues/114))
+
+
+
+## [v0.10.0] - 2026-07-10
+### Add
+- Add MovingAverage and MovingStdDev ([#112](https://github.com/montanaflynn/stats/issues/112))
+- Add ZScore and Rank functions ([#111](https://github.com/montanaflynn/stats/issues/111))
+- Add WeightedMean and CoefficientOfVariation ([#110](https://github.com/montanaflynn/stats/issues/110))
+- Add ArgMax, ArgMin and Range functions ([#109](https://github.com/montanaflynn/stats/issues/109))
+- Add CumulativeProduct, CumulativeMax and CumulativeMin ([#108](https://github.com/montanaflynn/stats/issues/108))
+- Add Diff and PercentChange functions ([#107](https://github.com/montanaflynn/stats/issues/107))
+- Add weighted percentile function ([#102](https://github.com/montanaflynn/stats/issues/102))
+- Add NormSample function for normal distribution sampling ([#100](https://github.com/montanaflynn/stats/issues/100))
+- Add Z-test and T-test functions ([#99](https://github.com/montanaflynn/stats/issues/99))
+- Add Spearman rank correlation function ([#98](https://github.com/montanaflynn/stats/issues/98))
+
+### Fix
+- Stabilize GeometricMean and add input validation
+- Use math.Round to avoid ARM64 FMA fusion miscompile ([#97](https://github.com/montanaflynn/stats/issues/97))
+- Correct AutoCorrelation lag handling ([#83](https://github.com/montanaflynn/stats/issues/83)) ([#95](https://github.com/montanaflynn/stats/issues/95))
+
+
+
+## [v0.10.0] - 2026-07-10
+### Add
+- Add MovingAverage and MovingStdDev ([#112](https://github.com/montanaflynn/stats/issues/112))
+- Add ZScore and Rank functions ([#111](https://github.com/montanaflynn/stats/issues/111))
+- Add WeightedMean and CoefficientOfVariation ([#110](https://github.com/montanaflynn/stats/issues/110))
+- Add ArgMax, ArgMin and Range functions ([#109](https://github.com/montanaflynn/stats/issues/109))
+- Add CumulativeProduct, CumulativeMax and CumulativeMin ([#108](https://github.com/montanaflynn/stats/issues/108))
+- Add Diff and PercentChange functions ([#107](https://github.com/montanaflynn/stats/issues/107))
+- Add weighted percentile function ([#102](https://github.com/montanaflynn/stats/issues/102))
+- Add NormSample function for normal distribution sampling ([#100](https://github.com/montanaflynn/stats/issues/100))
+- Add Z-test and T-test functions ([#99](https://github.com/montanaflynn/stats/issues/99))
+- Add Spearman rank correlation function ([#98](https://github.com/montanaflynn/stats/issues/98))
+
+### Fix
+- Stabilize GeometricMean and add input validation
+- Use math.Round to avoid ARM64 FMA fusion miscompile ([#97](https://github.com/montanaflynn/stats/issues/97))
+- Correct AutoCorrelation lag handling ([#83](https://github.com/montanaflynn/stats/issues/83)) ([#95](https://github.com/montanaflynn/stats/issues/95))
+
+
+
+## [v0.9.0] - 2026-03-24
+### Add
+- Add Skewness, PopulationSkewness, and SampleSkewness functions ([#91](https://github.com/montanaflynn/stats/issues/91))
+
+### Fix
+- Restore 100% test coverage for skewness
+- Remove unused sum[4] in LinearRegression
+
+
+
+## [v0.8.2] - 2026-03-11
+
+
+## [v0.8.1] - 2026-03-11
+
## [v0.8.0] - 2026-03-11
### Fix
@@ -527,7 +598,13 @@
- Merge pull request [#4](https://github.com/montanaflynn/stats/issues/4) from saromanov/sample
-[Unreleased]: https://github.com/montanaflynn/stats/compare/v0.8.0...HEAD
+[Unreleased]: https://github.com/montanaflynn/stats/compare/v0.11.0...HEAD
+[v0.11.0]: https://github.com/montanaflynn/stats/compare/v0.10.0...v0.11.0
+[v0.10.0]: https://github.com/montanaflynn/stats/compare/v0.9.0...v0.10.0
+[v0.10.0]: https://github.com/montanaflynn/stats/compare/v0.9.0...v0.10.0
+[v0.9.0]: https://github.com/montanaflynn/stats/compare/v0.8.2...v0.9.0
+[v0.8.2]: https://github.com/montanaflynn/stats/compare/v0.8.1...v0.8.2
+[v0.8.1]: https://github.com/montanaflynn/stats/compare/v0.8.0...v0.8.1
[v0.8.0]: https://github.com/montanaflynn/stats/compare/v0.7.1...v0.8.0
[v0.7.1]: https://github.com/montanaflynn/stats/compare/v0.7.0...v0.7.1
[v0.7.0]: https://github.com/montanaflynn/stats/compare/v0.6.6...v0.7.0
diff --git a/vendor/github.com/montanaflynn/stats/DOCUMENTATION.md b/vendor/github.com/montanaflynn/stats/DOCUMENTATION.md
index 32ec075..0dc1c0d 100644
--- a/vendor/github.com/montanaflynn/stats/DOCUMENTATION.md
+++ b/vendor/github.com/montanaflynn/stats/DOCUMENTATION.md
@@ -36,18 +36,31 @@ MIT License Copyright (c) 2014-2026 Montana Flynn (Index
* [Variables](#pkg-variables)
+* [func ArgMax(input Float64Data) (int, error)](#ArgMax)
+* [func ArgMin(input Float64Data) (int, error)](#ArgMin)
* [func AutoCorrelation(data Float64Data, lags int) (float64, error)](#AutoCorrelation)
* [func ChebyshevDistance(dataPointX, dataPointY Float64Data) (distance float64, err error)](#ChebyshevDistance)
+* [func Clip(input Float64Data, min, max float64) ([]float64, error)](#Clip)
+* [func CoefficientOfVariation(input Float64Data) (float64, error)](#CoefficientOfVariation)
* [func Correlation(data1, data2 Float64Data) (float64, error)](#Correlation)
* [func Covariance(data1, data2 Float64Data) (float64, error)](#Covariance)
* [func CovariancePopulation(data1, data2 Float64Data) (float64, error)](#CovariancePopulation)
+* [func CumulativeMax(input Float64Data) ([]float64, error)](#CumulativeMax)
+* [func CumulativeMin(input Float64Data) ([]float64, error)](#CumulativeMin)
+* [func CumulativeProduct(input Float64Data) ([]float64, error)](#CumulativeProduct)
* [func CumulativeSum(input Float64Data) ([]float64, error)](#CumulativeSum)
+* [func Diff(input Float64Data) ([]float64, error)](#Diff)
+* [func EWMA(input Float64Data, alpha float64) ([]float64, error)](#EWMA)
* [func Entropy(input Float64Data) (float64, error)](#Entropy)
* [func EuclideanDistance(dataPointX, dataPointY Float64Data) (distance float64, err error)](#EuclideanDistance)
* [func ExpGeom(p float64) (exp float64, err error)](#ExpGeom)
* [func GeometricMean(input Float64Data) (float64, error)](#GeometricMean)
* [func HarmonicMean(input Float64Data) (float64, error)](#HarmonicMean)
+* [func Histogram(input Float64Data, bins int) ([]int, []float64, error)](#Histogram)
* [func InterQuartileRange(input Float64Data) (float64, error)](#InterQuartileRange)
+* [func Interp(x, xp, fp Float64Data) ([]float64, error)](#Interp)
+* [func KendallTau(data1, data2 Float64Data) (float64, error)](#KendallTau)
+* [func Kurtosis(input Float64Data) (float64, error)](#Kurtosis)
* [func ManhattanDistance(dataPointX, dataPointY Float64Data) (distance float64, err error)](#ManhattanDistance)
* [func Max(input Float64Data) (max float64, err error)](#Max)
* [func Mean(input Float64Data) (float64, error)](#Mean)
@@ -58,6 +71,12 @@ MIT License Copyright (c) 2014-2026 Montana Flynn (Examples
+* [ArgMax](#example_ArgMax)
+* [ArgMin](#example_ArgMin)
* [AutoCorrelation](#example_AutoCorrelation)
* [ChebyshevDistance](#example_ChebyshevDistance)
+* [Clip](#example_Clip)
* [Correlation](#example_Correlation)
+* [CumulativeMax](#example_CumulativeMax)
+* [CumulativeMin](#example_CumulativeMin)
+* [CumulativeProduct](#example_CumulativeProduct)
* [CumulativeSum](#example_CumulativeSum)
+* [Diff](#example_Diff)
+* [EWMA](#example_EWMA)
* [Entropy](#example_Entropy)
* [ExpGeom](#example_ExpGeom)
+* [Histogram](#example_Histogram)
+* [Interp](#example_Interp)
+* [KendallTau](#example_KendallTau)
+* [Kurtosis](#example_Kurtosis)
* [LinearRegression](#example_LinearRegression)
* [LoadRawData](#example_LoadRawData)
* [Max](#example_Max)
* [Median](#example_Median)
* [Min](#example_Min)
+* [MovingAverage](#example_MovingAverage)
+* [MovingMax](#example_MovingMax)
+* [MovingMedian](#example_MovingMedian)
+* [MovingMin](#example_MovingMin)
+* [MovingStdDev](#example_MovingStdDev)
+* [MovingSum](#example_MovingSum)
+* [PercentChange](#example_PercentChange)
+* [PercentileOfScore](#example_PercentileOfScore)
* [ProbGeom](#example_ProbGeom)
+* [Product](#example_Product)
+* [RMS](#example_RMS)
+* [Range](#example_Range)
+* [Rank](#example_Rank)
+* [Rescale](#example_Rescale)
* [Round](#example_Round)
+* [SEM](#example_SEM)
+* [SampleKurtosis](#example_SampleKurtosis)
* [Sigmoid](#example_Sigmoid)
* [SoftMax](#example_SoftMax)
+* [Spearman](#example_Spearman)
* [Sum](#example_Sum)
+* [TrimmedMean](#example_TrimmedMean)
* [VarGeom](#example_VarGeom)
+* [Winsorize](#example_Winsorize)
+* [ZScore](#example_ZScore)
#### Package files
-[correlation.go](/src/github.com/montanaflynn/stats/correlation.go) [cumulative_sum.go](/src/github.com/montanaflynn/stats/cumulative_sum.go) [data.go](/src/github.com/montanaflynn/stats/data.go) [describe.go](/src/github.com/montanaflynn/stats/describe.go) [deviation.go](/src/github.com/montanaflynn/stats/deviation.go) [distances.go](/src/github.com/montanaflynn/stats/distances.go) [doc.go](/src/github.com/montanaflynn/stats/doc.go) [entropy.go](/src/github.com/montanaflynn/stats/entropy.go) [errors.go](/src/github.com/montanaflynn/stats/errors.go) [geometric_distribution.go](/src/github.com/montanaflynn/stats/geometric_distribution.go) [legacy.go](/src/github.com/montanaflynn/stats/legacy.go) [load.go](/src/github.com/montanaflynn/stats/load.go) [max.go](/src/github.com/montanaflynn/stats/max.go) [mean.go](/src/github.com/montanaflynn/stats/mean.go) [median.go](/src/github.com/montanaflynn/stats/median.go) [min.go](/src/github.com/montanaflynn/stats/min.go) [mode.go](/src/github.com/montanaflynn/stats/mode.go) [norm.go](/src/github.com/montanaflynn/stats/norm.go) [outlier.go](/src/github.com/montanaflynn/stats/outlier.go) [percentile.go](/src/github.com/montanaflynn/stats/percentile.go) [quartile.go](/src/github.com/montanaflynn/stats/quartile.go) [ranksum.go](/src/github.com/montanaflynn/stats/ranksum.go) [regression.go](/src/github.com/montanaflynn/stats/regression.go) [round.go](/src/github.com/montanaflynn/stats/round.go) [sample.go](/src/github.com/montanaflynn/stats/sample.go) [sigmoid.go](/src/github.com/montanaflynn/stats/sigmoid.go) [softmax.go](/src/github.com/montanaflynn/stats/softmax.go) [sum.go](/src/github.com/montanaflynn/stats/sum.go) [util.go](/src/github.com/montanaflynn/stats/util.go) [variance.go](/src/github.com/montanaflynn/stats/variance.go)
+[clip.go](/src/github.com/montanaflynn/stats/clip.go) [coefficient_of_variation.go](/src/github.com/montanaflynn/stats/coefficient_of_variation.go) [correlation.go](/src/github.com/montanaflynn/stats/correlation.go) [cumulative.go](/src/github.com/montanaflynn/stats/cumulative.go) [cumulative_sum.go](/src/github.com/montanaflynn/stats/cumulative_sum.go) [data.go](/src/github.com/montanaflynn/stats/data.go) [describe.go](/src/github.com/montanaflynn/stats/describe.go) [deviation.go](/src/github.com/montanaflynn/stats/deviation.go) [diff.go](/src/github.com/montanaflynn/stats/diff.go) [distances.go](/src/github.com/montanaflynn/stats/distances.go) [doc.go](/src/github.com/montanaflynn/stats/doc.go) [entropy.go](/src/github.com/montanaflynn/stats/entropy.go) [errors.go](/src/github.com/montanaflynn/stats/errors.go) [ewma.go](/src/github.com/montanaflynn/stats/ewma.go) [extremes.go](/src/github.com/montanaflynn/stats/extremes.go) [geometric_distribution.go](/src/github.com/montanaflynn/stats/geometric_distribution.go) [histogram.go](/src/github.com/montanaflynn/stats/histogram.go) [interp.go](/src/github.com/montanaflynn/stats/interp.go) [kendall.go](/src/github.com/montanaflynn/stats/kendall.go) [kurtosis.go](/src/github.com/montanaflynn/stats/kurtosis.go) [legacy.go](/src/github.com/montanaflynn/stats/legacy.go) [load.go](/src/github.com/montanaflynn/stats/load.go) [max.go](/src/github.com/montanaflynn/stats/max.go) [mean.go](/src/github.com/montanaflynn/stats/mean.go) [median.go](/src/github.com/montanaflynn/stats/median.go) [min.go](/src/github.com/montanaflynn/stats/min.go) [mode.go](/src/github.com/montanaflynn/stats/mode.go) [moving.go](/src/github.com/montanaflynn/stats/moving.go) [norm.go](/src/github.com/montanaflynn/stats/norm.go) [outlier.go](/src/github.com/montanaflynn/stats/outlier.go) [percentile.go](/src/github.com/montanaflynn/stats/percentile.go) [percentile_of_score.go](/src/github.com/montanaflynn/stats/percentile_of_score.go) [percentile_weighted.go](/src/github.com/montanaflynn/stats/percentile_weighted.go) [product.go](/src/github.com/montanaflynn/stats/product.go) [quartile.go](/src/github.com/montanaflynn/stats/quartile.go) [rank.go](/src/github.com/montanaflynn/stats/rank.go) [ranksum.go](/src/github.com/montanaflynn/stats/ranksum.go) [regression.go](/src/github.com/montanaflynn/stats/regression.go) [rescale.go](/src/github.com/montanaflynn/stats/rescale.go) [rms.go](/src/github.com/montanaflynn/stats/rms.go) [rolling.go](/src/github.com/montanaflynn/stats/rolling.go) [round.go](/src/github.com/montanaflynn/stats/round.go) [sample.go](/src/github.com/montanaflynn/stats/sample.go) [sem.go](/src/github.com/montanaflynn/stats/sem.go) [sigmoid.go](/src/github.com/montanaflynn/stats/sigmoid.go) [skewness.go](/src/github.com/montanaflynn/stats/skewness.go) [softmax.go](/src/github.com/montanaflynn/stats/softmax.go) [sum.go](/src/github.com/montanaflynn/stats/sum.go) [trimmed_mean.go](/src/github.com/montanaflynn/stats/trimmed_mean.go) [ttest.go](/src/github.com/montanaflynn/stats/ttest.go) [util.go](/src/github.com/montanaflynn/stats/util.go) [variance.go](/src/github.com/montanaflynn/stats/variance.go) [weighted_mean.go](/src/github.com/montanaflynn/stats/weighted_mean.go) [winsorize.go](/src/github.com/montanaflynn/stats/winsorize.go) [zscore.go](/src/github.com/montanaflynn/stats/zscore.go) [ztest.go](/src/github.com/montanaflynn/stats/ztest.go)
@@ -223,7 +328,25 @@ Legacy error names that didn't start with Err
-## func [AutoCorrelation](/correlation.go?s=853:918#L38)
+## func [ArgMax](/extremes.go?s=129:172#L5)
+``` go
+func ArgMax(input Float64Data) (int, error)
+```
+ArgMax finds the index of the highest number in a slice,
+returning the first occurrence in the case of ties
+
+
+
+## func [ArgMin](/extremes.go?s=671:714#L28)
+``` go
+func ArgMin(input Float64Data) (int, error)
+```
+ArgMin finds the index of the lowest number in a slice,
+returning the first occurrence in the case of ties
+
+
+
+## func [AutoCorrelation](/correlation.go?s=2282:2347#L102)
``` go
func AutoCorrelation(data Float64Data, lags int) (float64, error)
```
@@ -239,7 +362,29 @@ ChebyshevDistance computes the Chebyshev distance between two data sets
-## func [Correlation](/correlation.go?s=112:171#L8)
+## func [Clip](/clip.go?s=109:174#L5)
+``` go
+func Clip(input Float64Data, min, max float64) ([]float64, error)
+```
+Clip clamps each value in the input slice into the
+inclusive range between min and max.
+
+
+
+## func [CoefficientOfVariation](/coefficient_of_variation.go?s=322:385#L11)
+``` go
+func CoefficientOfVariation(input Float64Data) (float64, error)
+```
+CoefficientOfVariation finds the coefficient of variation of a slice
+of floats, defined as the sample standard deviation divided by the
+mean. This matches the behavior of Python's scipy.stats.variation
+with ddof=1.
+
+The input must not be empty and its mean must not be zero.
+
+
+
+## func [Correlation](/correlation.go?s=120:179#L9)
``` go
func Correlation(data1, data2 Float64Data) (float64, error)
```
@@ -263,6 +408,30 @@ CovariancePopulation computes covariance for entire population between two varia
+## func [CumulativeMax](/cumulative.go?s=486:542#L24)
+``` go
+func CumulativeMax(input Float64Data) ([]float64, error)
+```
+CumulativeMax calculates the cumulative maximum of the input slice
+
+
+
+## func [CumulativeMin](/cumulative.go?s=874:930#L44)
+``` go
+func CumulativeMin(input Float64Data) ([]float64, error)
+```
+CumulativeMin calculates the cumulative minimum of the input slice
+
+
+
+## func [CumulativeProduct](/cumulative.go?s=89:149#L4)
+``` go
+func CumulativeProduct(input Float64Data) ([]float64, error)
+```
+CumulativeProduct calculates the cumulative product of the input slice
+
+
+
## func [CumulativeSum](/cumulative_sum.go?s=81:137#L4)
``` go
func CumulativeSum(input Float64Data) ([]float64, error)
@@ -271,6 +440,30 @@ CumulativeSum calculates the cumulative sum of the input slice
+## func [Diff](/diff.go?s=238:285#L7)
+``` go
+func Diff(input Float64Data) ([]float64, error)
+```
+Diff calculates the successive differences of the input slice,
+returning input[i] - input[i-1] for each i in 1..len(input)-1.
+The output has length len(input) - 1; a single-element input
+returns an empty slice.
+
+
+
+## func [EWMA](/ewma.go?s=392:454#L9)
+``` go
+func EWMA(input Float64Data, alpha float64) ([]float64, error)
+```
+EWMA calculates the exponentially weighted moving average of the input
+with smoothing factor alpha. The first output equals the first input and
+each subsequent entry is alpha*input[i] + (1-alpha)*output[i-1], so the
+result has the same length as the input. The alpha must satisfy
+0 < alpha <= 1 or ErrBounds is returned. An empty input returns
+ErrEmptyInput.
+
+
+
## func [Entropy](/entropy.go?s=77:125#L6)
``` go
func Entropy(input Float64Data) (float64, error)
@@ -304,7 +497,7 @@ GeometricMean gets the geometric mean for a slice of numbers
-## func [HarmonicMean](/mean.go?s=717:770#L40)
+## func [HarmonicMean](/mean.go?s=842:895#L41)
``` go
func HarmonicMean(input Float64Data) (float64, error)
```
@@ -312,6 +505,18 @@ HarmonicMean gets the harmonic mean for a slice of numbers
+## func [Histogram](/histogram.go?s=327:396#L10)
+``` go
+func Histogram(input Float64Data, bins int) ([]int, []float64, error)
+```
+Histogram calculates the histogram of a slice using the given
+number of equal-width bins over [min, max], returning the count
+of values in each bin along with the bins+1 bin edges. Each bin
+is half-open [edges[i], edges[i+1]) except the last, which also
+includes the maximum value.
+
+
+
## func [InterQuartileRange](/quartile.go?s=821:880#L45)
``` go
func InterQuartileRange(input Float64Data) (float64, error)
@@ -320,6 +525,39 @@ InterQuartileRange finds the range between Q1 and Q3
+## func [Interp](/interp.go?s=547:600#L12)
+``` go
+func Interp(x, xp, fp Float64Data) ([]float64, error)
+```
+Interp calculates the one-dimensional piecewise-linear interpolant to a
+function with given discrete data points (xp, fp), evaluated at each x.
+Values of x below xp[0] return fp[0] and values above xp[len(xp)-1] return
+fp[len(xp)-1], so no extrapolation is performed. Unlike numpy's interp,
+which silently returns nonsense for unsorted coordinates, xp must be
+strictly increasing or ErrBounds is returned. An empty x or xp returns
+ErrEmptyInput and xp and fp of different lengths return ErrSize.
+
+
+
+## func [KendallTau](/kendall.go?s=302:360#L9)
+``` go
+func KendallTau(data1, data2 Float64Data) (float64, error)
+```
+KendallTau calculates Kendall's tau-b rank correlation coefficient
+between two variables. Tau-b corrects for ties, matching the values
+produced by SciPy's kendalltau and pandas' corr(method="kendall").
+Pairs are compared with a simple O(n^2) loop for clarity.
+
+
+
+## func [Kurtosis](/kurtosis.go?s=97:146#L6)
+``` go
+func Kurtosis(input Float64Data) (float64, error)
+```
+Kurtosis computes the population excess kurtosis of the dataset
+
+
+
## func [ManhattanDistance](/distances.go?s=1277:1365#L50)
``` go
func ManhattanDistance(dataPointX, dataPointY Float64Data) (distance float64, err error)
@@ -417,7 +655,81 @@ Mode gets the mode [most frequent value(s)] of a slice of float64s
-## func [Ncr](/norm.go?s=7384:7406#L239)
+## func [MovingAverage](/rolling.go?s=362:430#L8)
+``` go
+func MovingAverage(input Float64Data, window int) ([]float64, error)
+```
+MovingAverage calculates the rolling mean of the input over a trailing
+window. Only fully-populated windows produce output, so the result has
+len(input)-window+1 entries and entry i is the mean of input[i : i+window].
+The window must satisfy 1 <= window <= len(input) or ErrBounds is
+returned. An empty input returns ErrEmptyInput.
+
+
+
+## func [MovingMax](/moving.go?s=1892:1956#L60)
+``` go
+func MovingMax(input Float64Data, window int) ([]float64, error)
+```
+MovingMax calculates the rolling maximum of the input over a trailing
+window. Only fully-populated windows produce output, so the result has
+len(input)-window+1 entries and entry i is the maximum of
+input[i : i+window]. The window must satisfy 1 <= window <= len(input) or
+ErrBounds is returned. An empty input returns ErrEmptyInput.
+
+
+
+## func [MovingMedian](/moving.go?s=365:432#L8)
+``` go
+func MovingMedian(input Float64Data, window int) ([]float64, error)
+```
+MovingMedian calculates the rolling median of the input over a trailing
+window. Only fully-populated windows produce output, so the result has
+len(input)-window+1 entries and entry i is the median of input[i : i+window].
+The window must satisfy 1 <= window <= len(input) or ErrBounds is
+returned. An empty input returns ErrEmptyInput.
+
+
+
+## func [MovingMin](/moving.go?s=1136:1200#L34)
+``` go
+func MovingMin(input Float64Data, window int) ([]float64, error)
+```
+MovingMin calculates the rolling minimum of the input over a trailing
+window. Only fully-populated windows produce output, so the result has
+len(input)-window+1 entries and entry i is the minimum of
+input[i : i+window]. The window must satisfy 1 <= window <= len(input) or
+ErrBounds is returned. An empty input returns ErrEmptyInput.
+
+
+
+## func [MovingStdDev](/rolling.go?s=1239:1306#L36)
+``` go
+func MovingStdDev(input Float64Data, window int) ([]float64, error)
+```
+MovingStdDev calculates the rolling sample standard deviation of the input
+over a trailing window. Only fully-populated windows produce output, so the
+result has len(input)-window+1 entries and entry i is the sample standard
+deviation of input[i : i+window]. The window must satisfy
+2 <= window <= len(input) or ErrBounds is returned, since the sample
+standard deviation of a single value is undefined. An empty input returns
+ErrEmptyInput.
+
+
+
+## func [MovingSum](/moving.go?s=2640:2704#L86)
+``` go
+func MovingSum(input Float64Data, window int) ([]float64, error)
+```
+MovingSum calculates the rolling sum of the input over a trailing
+window. Only fully-populated windows produce output, so the result has
+len(input)-window+1 entries and entry i is the sum of input[i : i+window].
+The window must satisfy 1 <= window <= len(input) or ErrBounds is
+returned. An empty input returns ErrEmptyInput.
+
+
+
+## func [Ncr](/norm.go?s=7623:7645#L245)
``` go
func Ncr(n, r int) int
```
@@ -426,7 +738,7 @@ Aaron Cannon's algorithm.
-## func [NormBoxMullerRvs](/norm.go?s=667:736#L23)
+## func [NormBoxMullerRvs](/norm.go?s=906:975#L29)
``` go
func NormBoxMullerRvs(loc float64, scale float64, size int) []float64
```
@@ -435,7 +747,7 @@ For more information please visit: func [NormCdf](/norm.go?s=1826:1885#L52)
+## func [NormCdf](/norm.go?s=2065:2124#L58)
``` go
func NormCdf(x float64, loc float64, scale float64) float64
```
@@ -443,7 +755,7 @@ NormCdf is the cumulative distribution function.
-## func [NormEntropy](/norm.go?s=5773:5825#L180)
+## func [NormEntropy](/norm.go?s=6012:6064#L186)
``` go
func NormEntropy(loc float64, scale float64) float64
```
@@ -451,7 +763,7 @@ NormEntropy is the differential entropy of the RV.
-## func [NormFit](/norm.go?s=6058:6097#L187)
+## func [NormFit](/norm.go?s=6297:6336#L193)
``` go
func NormFit(data []float64) [2]float64
```
@@ -461,7 +773,7 @@ Returns array of Mean followed by Standard Deviation.
-## func [NormInterval](/norm.go?s=6976:7047#L221)
+## func [NormInterval](/norm.go?s=7215:7286#L227)
``` go
func NormInterval(alpha float64, loc float64, scale float64) [2]float64
```
@@ -469,7 +781,7 @@ NormInterval finds endpoints of the range that contains alpha percent of the dis
-## func [NormIsf](/norm.go?s=4330:4393#L137)
+## func [NormIsf](/norm.go?s=4569:4632#L143)
``` go
func NormIsf(p float64, loc float64, scale float64) (x float64)
```
@@ -477,7 +789,7 @@ NormIsf is the inverse survival function (inverse of sf).
-## func [NormLogCdf](/norm.go?s=2016:2078#L57)
+## func [NormLogCdf](/norm.go?s=2255:2317#L63)
``` go
func NormLogCdf(x float64, loc float64, scale float64) float64
```
@@ -485,7 +797,7 @@ NormLogCdf is the log of the cumulative distribution function.
-## func [NormLogPdf](/norm.go?s=1590:1652#L47)
+## func [NormLogPdf](/norm.go?s=1829:1891#L53)
``` go
func NormLogPdf(x float64, loc float64, scale float64) float64
```
@@ -493,7 +805,7 @@ NormLogPdf is the log of the probability density function.
-## func [NormLogSf](/norm.go?s=2423:2484#L67)
+## func [NormLogSf](/norm.go?s=2662:2723#L73)
``` go
func NormLogSf(x float64, loc float64, scale float64) float64
```
@@ -501,7 +813,7 @@ NormLogSf is the log of the survival function.
-## func [NormMean](/norm.go?s=6560:6609#L206)
+## func [NormMean](/norm.go?s=6799:6848#L212)
``` go
func NormMean(loc float64, scale float64) float64
```
@@ -509,7 +821,7 @@ NormMean is the mean/expected value of the distribution.
-## func [NormMedian](/norm.go?s=6431:6482#L201)
+## func [NormMedian](/norm.go?s=6670:6721#L207)
``` go
func NormMedian(loc float64, scale float64) float64
```
@@ -517,7 +829,7 @@ NormMedian is the median of the distribution.
-## func [NormMoment](/norm.go?s=4694:4752#L146)
+## func [NormMoment](/norm.go?s=4933:4991#L152)
``` go
func NormMoment(n int, loc float64, scale float64) float64
```
@@ -526,7 +838,7 @@ For more information please visit: func [NormPdf](/norm.go?s=1357:1416#L42)
+## func [NormPdf](/norm.go?s=1596:1655#L48)
``` go
func NormPdf(x float64, loc float64, scale float64) float64
```
@@ -534,7 +846,7 @@ NormPdf is the probability density function.
-## func [NormPpf](/norm.go?s=2854:2917#L75)
+## func [NormPpf](/norm.go?s=3093:3156#L81)
``` go
func NormPpf(p float64, loc float64, scale float64) (x float64)
```
@@ -545,7 +857,7 @@ For more information please visit: func [NormPpfRvs](/norm.go?s=247:310#L12)
+## func [NormPpfRvs](/norm.go?s=486:549#L18)
``` go
func NormPpfRvs(loc float64, scale float64, size int) []float64
```
@@ -554,7 +866,16 @@ For more information please visit: func [NormSf](/norm.go?s=2250:2308#L62)
+## func [NormSample](/norm.go?s=194:257#L12)
+``` go
+func NormSample(loc float64, scale float64, size int) []float64
+```
+NormSample generates random samples from a normal distribution
+with the given mean (loc) and standard deviation (scale).
+
+
+
+## func [NormSf](/norm.go?s=2489:2547#L68)
``` go
func NormSf(x float64, loc float64, scale float64) float64
```
@@ -562,7 +883,7 @@ NormSf is the survival function (also defined as 1 - cdf, but sf is sometimes mo
-## func [NormStats](/norm.go?s=5277:5345#L162)
+## func [NormStats](/norm.go?s=5516:5584#L168)
``` go
func NormStats(loc float64, scale float64, moments string) []float64
```
@@ -573,7 +894,7 @@ Returns array of m v s k in that order.
-## func [NormStd](/norm.go?s=6814:6862#L216)
+## func [NormStd](/norm.go?s=7053:7101#L222)
``` go
func NormStd(loc float64, scale float64) float64
```
@@ -581,7 +902,7 @@ NormStd is the standard deviation of the distribution.
-## func [NormVar](/norm.go?s=6675:6723#L211)
+## func [NormVar](/norm.go?s=6914:6962#L217)
``` go
func NormVar(loc float64, scale float64) float64
```
@@ -589,7 +910,7 @@ NormVar is the variance of the distribution.
-## func [Pearson](/correlation.go?s=655:710#L33)
+## func [Pearson](/correlation.go?s=663:718#L34)
``` go
func Pearson(data1, data2 Float64Data) (float64, error)
```
@@ -597,6 +918,20 @@ Pearson calculates the Pearson product-moment correlation coefficient between tw
+## func [PercentChange](/diff.go?s=891:947#L29)
+``` go
+func PercentChange(input Float64Data) ([]float64, error)
+```
+PercentChange calculates the fractional change between successive
+elements of the input slice, returning
+(input[i] - input[i-1]) / input[i-1] for each i in 1..len(input)-1.
+The output has length len(input) - 1; a single-element input
+returns an empty slice. A zero denominator follows IEEE 754
+semantics, yielding +Inf, -Inf, or NaN (for 0/0), matching the
+behavior of pandas pct_change.
+
+
+
## func [Percentile](/percentile.go?s=598:681#L20)
``` go
func Percentile(input Float64Data, percent float64) (percentile float64, err error)
@@ -626,6 +961,56 @@ PercentileNearestRank finds the relative standing in a slice of floats using the
+## func [PercentileOfScore](/percentile_of_score.go?s=374:447#L11)
+``` go
+func PercentileOfScore(input Float64Data, score float64) (float64, error)
+```
+PercentileOfScore calculates the percentile rank of a score
+relative to a slice of floats, defined as the percentage of
+values strictly below the score plus half the percentage of
+values equal to the score. The result is between 0 and 100.
+This matches the behavior of Python's
+scipy.stats.percentileofscore with kind="rank".
+
+
+
+## func [PercentileWeighted](/percentile_weighted.go?s=620:719#L19)
+``` go
+func PercentileWeighted(data, weights Float64Data, percent float64) (percentile float64, err error)
+```
+PercentileWeighted finds the weighted percentile of a slice of floats
+using the weighted empirical CDF (inverse CDF / nearest-rank method).
+
+For a given percent p, it returns the smallest data value x such that
+the cumulative weight of all values <= x is at least p% of the total
+weight. This matches the behavior of Python's statsmodels
+DescrStatsW.quantile.
+
+The data and weights slices must be the same length. Weights must be
+non-negative and at least one weight must be positive. The percent
+parameter must be between 0 and 100 (exclusive).
+
+
+
+## func [PopulationKurtosis](/kurtosis.go?s=391:450#L13)
+``` go
+func PopulationKurtosis(input Float64Data) (float64, error)
+```
+PopulationKurtosis computes the population excess kurtosis (Fisher
+definition) using the fourth central moment normalized by the squared
+variance, so a normal distribution has a kurtosis of zero.
+
+
+
+## func [PopulationSkewness](/skewness.go?s=318:377#L12)
+``` go
+func PopulationSkewness(input Float64Data) (float64, error)
+```
+PopulationSkewness computes the population skewness using the third
+central moment normalized by the cube of the standard deviation.
+
+
+
## func [PopulationVariance](/variance.go?s=828:896#L31)
``` go
func PopulationVariance(input Float64Data) (pvar float64, err error)
@@ -644,6 +1029,56 @@ See https://en.wi
+## func [Product](/product.go?s=299:347#L10)
+``` go
+func Product(input Float64Data) (float64, error)
+```
+Product calculates the product of a slice of floats by
+multiplying the values from left to right. It is the scalar
+counterpart of CumulativeProduct. Large inputs can overflow
+to Inf; use GeometricMean for an overflow-safe summary of
+multiplicative data.
+
+
+
+## func [RMS](/rms.go?s=156:200#L7)
+``` go
+func RMS(input Float64Data) (float64, error)
+```
+RMS calculates the root mean square of a slice of floats,
+defined as the square root of the mean of the squared values.
+
+
+
+## func [Range](/extremes.go?s=1181:1227#L51)
+``` go
+func Range(input Float64Data) (float64, error)
+```
+Range finds the difference between the highest and
+lowest numbers in a slice
+
+
+
+## func [Rank](/rank.go?s=183:230#L6)
+``` go
+func Rank(input Float64Data) ([]float64, error)
+```
+Rank assigns fractional (average) ranks to the input values.
+Ranks are 1-based and tied values receive the average of the
+ranks they would have been assigned.
+
+
+
+## func [Rescale](/rescale.go?s=174:224#L6)
+``` go
+func Rescale(input Float64Data) ([]float64, error)
+```
+Rescale normalizes the input values to the range of 0 to 1
+by subtracting the minimum and dividing by the range,
+also known as min-max normalization.
+
+
+
## func [Round](/round.go?s=88:154#L6)
``` go
func Round(input float64, places int) (rounded float64, err error)
@@ -652,6 +1087,17 @@ Round a float to a specific decimal place or precision
+## func [SEM](/sem.go?s=265:309#L9)
+``` go
+func SEM(input Float64Data) (float64, error)
+```
+SEM calculates the standard error of the mean of a slice
+of floats, defined as the sample standard deviation divided
+by the square root of the sample size. This matches the
+behavior of Python's scipy.stats.sem with ddof=1.
+
+
+
## func [Sample](/sample.go?s=112:192#L9)
``` go
func Sample(input Float64Data, takenum int, replacement bool) ([]float64, error)
@@ -660,6 +1106,24 @@ Sample returns sample from input with replacement or without
+## func [SampleKurtosis](/kurtosis.go?s=1071:1126#L41)
+``` go
+func SampleKurtosis(input Float64Data) (float64, error)
+```
+SampleKurtosis computes the bias-corrected sample excess kurtosis,
+matching pandas .kurt() and scipy.stats.kurtosis with bias=False.
+
+
+
+## func [SampleSkewness](/skewness.go?s=1049:1104#L44)
+``` go
+func SampleSkewness(input Float64Data) (float64, error)
+```
+SampleSkewness computes the adjusted Fisher-Pearson standardized moment
+coefficient, correcting for bias in small samples.
+
+
+
## func [SampleVariance](/variance.go?s=1058:1122#L42)
``` go
func SampleVariance(input Float64Data) (svar float64, err error)
@@ -679,6 +1143,14 @@ activation function.
+## func [Skewness](/skewness.go?s=90:139#L6)
+``` go
+func Skewness(input Float64Data) (float64, error)
+```
+Skewness computes the population skewness of the dataset
+
+
+
## func [SoftMax](/softmax.go?s=206:256#L8)
``` go
func SoftMax(input Float64Data) ([]float64, error)
@@ -689,6 +1161,16 @@ is commonly used in machine learning neural networks.
+## func [Spearman](/correlation.go?s=1006:1062#L41)
+``` go
+func Spearman(data1, data2 Float64Data) (float64, error)
+```
+Spearman calculates the Spearman rank correlation coefficient between two variables.
+It works by ranking the data and then computing the Pearson correlation of the ranks.
+This method handles tied values using fractional (average) ranking.
+
+
+
## func [StableSample](/sample.go?s=974:1042#L50)
``` go
func StableSample(input Float64Data, takenum int) ([]float64, error)
@@ -745,6 +1227,24 @@ Sum adds all the numbers of a slice together
+## func [TTest](/ttest.go?s=505:604#L16)
+``` go
+func TTest(data1, data2 Float64Data, populationMean float64) (t float64, pvalue float64, err error)
+```
+TTest performs a one-sample or two-sample (independent) Student's t-test.
+
+For a one-sample t-test, pass the sample data as data1, nil for data2,
+and the expected population mean as populationMean.
+
+For a two-sample independent t-test (assuming equal variance), pass both
+sample datasets. The populationMean parameter is ignored in this case.
+
+Returns the t statistic and the two-tailed p-value.
+
+https://en.wikipedia.org/wiki/Student%27s_t-test
+
+
+
## func [Trimean](/quartile.go?s=1320:1368#L65)
``` go
func Trimean(input Float64Data) (float64, error)
@@ -753,6 +1253,21 @@ Trimean finds the average of the median and the midhinge
+## func [TrimmedMean](/trimmed_mean.go?s=450:519#L13)
+``` go
+func TrimmedMean(input Float64Data, percent float64) (float64, error)
+```
+TrimmedMean finds the mean of a slice of floats after removing a
+fraction of the smallest and largest values. This matches the
+behavior of Python's scipy.stats.trim_mean.
+
+The percent parameter is the fraction removed from each tail and
+must be in the range [0, 0.5). The number of elements trimmed from
+each tail is floor(len(input) * percent). A percent of zero returns
+the same result as Mean.
+
+
+
## func [VarGeom](/geometric_distribution.go?s=885:933#L37)
``` go
func VarGeom(p float64) (exp float64, err error)
@@ -786,6 +1301,67 @@ Variance the amount of variation in the dataset
+## func [WeightedMean](/weighted_mean.go?s=415:476#L12)
+``` go
+func WeightedMean(data, weights Float64Data) (float64, error)
+```
+WeightedMean finds the weighted mean of a slice of floats, defined as
+the sum of each data value multiplied by its weight divided by the sum
+of all the weights. This matches the behavior of Python's
+numpy.average with the weights argument.
+
+The data and weights slices must be the same length. Weights must be
+non-negative and at least one weight must be positive.
+
+
+
+## func [Winsorize](/winsorize.go?s=618:687#L16)
+``` go
+func Winsorize(input Float64Data, percent float64) ([]float64, error)
+```
+Winsorize limits the effect of outliers in a slice of floats by
+clamping a fraction of the smallest and largest values. This matches
+the behavior of Python's scipy.stats.mstats.winsorize with symmetric
+limits.
+
+The percent parameter is the fraction clamped in each tail and must
+be in the range [0, 0.5). With k = floor(len(input) * percent),
+values below the k-th smallest value are set to it and values above
+the k-th largest value are set to it. The returned slice preserves
+the original element order and a percent of zero returns a copy of
+the input.
+
+
+
+## func [ZScore](/zscore.go?s=205:254#L6)
+``` go
+func ZScore(input Float64Data) ([]float64, error)
+```
+ZScore standardizes the input values by subtracting the mean
+and dividing by the sample standard deviation, returning the
+number of standard deviations each value is from the mean.
+
+
+
+## func [ZTest](/ztest.go?s=537:654#L17)
+``` go
+func ZTest(data1, data2 Float64Data, populationMean, populationStdDev float64) (z float64, pvalue float64, err error)
+```
+ZTest performs a one-sample or two-sample Z-test.
+
+For a one-sample Z-test, pass the sample data as data1, nil for data2,
+the known population mean as populationMean, and the known population
+standard deviation as populationStdDev.
+
+For a two-sample Z-test, pass both sample datasets and the known population
+standard deviations. The populationMean parameter is ignored in this case.
+
+Returns the Z statistic and the two-tailed p-value.
+
+https://en.wikipedia.org/wiki/Z-test
+
+
+
## type [Coordinate](/regression.go?s=143:183#L9)
``` go
@@ -826,7 +1402,7 @@ LogReg is a shortcut to LogarithmicRegression
-## type [Description](/describe.go?s=89:349#L6)
+## type [Description](/describe.go?s=89:381#L6)
``` go
type Description struct {
Count int
@@ -834,6 +1410,7 @@ type Description struct {
Std float64
Max float64
Min float64
+ Range float64
DescriptionPercentiles []descriptionPercentile
AllowedNaN bool
}
@@ -847,14 +1424,14 @@ Holds information about the dataset provided to Describe
-### func [Describe](/describe.go?s=579:672#L23)
+### func [Describe](/describe.go?s=611:704#L24)
``` go
func Describe(input Float64Data, allowNaN bool, percentiles *[]float64) (*Description, error)
```
Describe generates descriptive statistics about a provided dataset, similar to python's pandas.describe()
-### func [DescribePercentileFunc](/describe.go?s=917:1084#L29)
+### func [DescribePercentileFunc](/describe.go?s=949:1116#L30)
``` go
func DescribePercentileFunc(input Float64Data, allowNaN bool, percentiles *[]float64, percentileFunc func(Float64Data, float64) (float64, error)) (*Description, error)
```
@@ -865,7 +1442,7 @@ Takes in a function to use for percentile calculation
-### func (\*Description) [String](/describe.go?s=2078:2127#L68)
+### func (\*Description) [String](/describe.go?s=2161:2210#L71)
``` go
func (d *Description) String(decimals int) string
```
@@ -877,6 +1454,7 @@ Represents the Description instance in a string format with specified number of
std 0.82
max 3.00
min 1.00
+ range 2.00
25.00% NaN
50.00% 1.50
75.00% 2.50
@@ -907,7 +1485,25 @@ LoadRawData parses and converts a slice of mixed data types to floats
-### func (Float64Data) [AutoCorrelation](/data.go?s=3257:3320#L91)
+### func (Float64Data) [ArgMax](/extremes.go?s=1521:1563#L66)
+``` go
+func (f Float64Data) ArgMax() (int, error)
+```
+ArgMax returns the index of the highest number in the data
+
+
+
+
+### func (Float64Data) [ArgMin](/extremes.go?s=1647:1689#L69)
+``` go
+func (f Float64Data) ArgMin() (int, error)
+```
+ArgMin returns the index of the lowest number in the data
+
+
+
+
+### func (Float64Data) [AutoCorrelation](/data.go?s=3274:3337#L91)
``` go
func (f Float64Data) AutoCorrelation(lags int) (float64, error)
```
@@ -916,7 +1512,26 @@ AutoCorrelation is the correlation of a signal with a delayed copy of itself as
-### func (Float64Data) [Correlation](/data.go?s=3058:3122#L86)
+### func (Float64Data) [Clip](/clip.go?s=550:612#L30)
+``` go
+func (f Float64Data) Clip(min, max float64) ([]float64, error)
+```
+Clip clamps each value in the input slice into the
+inclusive range between min and max.
+
+
+
+
+### func (Float64Data) [CoefficientOfVariation](/coefficient_of_variation.go?s=768:830#L29)
+``` go
+func (f Float64Data) CoefficientOfVariation() (float64, error)
+```
+CoefficientOfVariation finds the sample standard deviation divided by the mean
+
+
+
+
+### func (Float64Data) [Correlation](/data.go?s=3075:3139#L86)
``` go
func (f Float64Data) Correlation(d Float64Data) (float64, error)
```
@@ -925,7 +1540,7 @@ Correlation describes the degree of relationship between two sets of data
-### func (Float64Data) [Covariance](/data.go?s=4801:4864#L141)
+### func (Float64Data) [Covariance](/data.go?s=4996:5059#L146)
``` go
func (f Float64Data) Covariance(d Float64Data) (float64, error)
```
@@ -934,7 +1549,7 @@ Covariance is a measure of how much two sets of data change
-### func (Float64Data) [CovariancePopulation](/data.go?s=4983:5056#L146)
+### func (Float64Data) [CovariancePopulation](/data.go?s=5178:5251#L151)
``` go
func (f Float64Data) CovariancePopulation(d Float64Data) (float64, error)
```
@@ -943,6 +1558,33 @@ CovariancePopulation computes covariance for entire population between two varia
+### func (Float64Data) [CumulativeMax](/cumulative.go?s=1416:1471#L69)
+``` go
+func (f Float64Data) CumulativeMax() ([]float64, error)
+```
+CumulativeMax calculates the cumulative maximum of the data
+
+
+
+
+### func (Float64Data) [CumulativeMin](/cumulative.go?s=1565:1620#L74)
+``` go
+func (f Float64Data) CumulativeMin() ([]float64, error)
+```
+CumulativeMin calculates the cumulative minimum of the data
+
+
+
+
+### func (Float64Data) [CumulativeProduct](/cumulative.go?s=1259:1318#L64)
+``` go
+func (f Float64Data) CumulativeProduct() ([]float64, error)
+```
+CumulativeProduct calculates the cumulative product of the data
+
+
+
+
### func (Float64Data) [CumulativeSum](/data.go?s=883:938#L28)
``` go
func (f Float64Data) CumulativeSum() ([]float64, error)
@@ -952,7 +1594,25 @@ CumulativeSum returns the cumulative sum of the data
-### func (Float64Data) [Entropy](/data.go?s=5480:5527#L162)
+### func (Float64Data) [Diff](/diff.go?s=1220:1266#L45)
+``` go
+func (f Float64Data) Diff() ([]float64, error)
+```
+Diff returns the successive differences of the data
+
+
+
+
+### func (Float64Data) [EWMA](/ewma.go?s=848:907#L30)
+``` go
+func (f Float64Data) EWMA(alpha float64) ([]float64, error)
+```
+EWMA returns the exponentially weighted moving average of the data with smoothing factor alpha
+
+
+
+
+### func (Float64Data) [Entropy](/data.go?s=5675:5722#L167)
``` go
func (f Float64Data) Entropy() (float64, error)
```
@@ -961,11 +1621,11 @@ Entropy provides calculation of the entropy
-### func (Float64Data) [GeometricMean](/data.go?s=1332:1385#L40)
+### func (Float64Data) [GeometricMean](/data.go?s=1340:1393#L40)
``` go
func (f Float64Data) GeometricMean() (float64, error)
```
-GeometricMean returns the median of the data
+GeometricMean returns the geometric mean of the data
@@ -979,16 +1639,25 @@ Get item in slice
-### func (Float64Data) [HarmonicMean](/data.go?s=1460:1512#L43)
+### func (Float64Data) [HarmonicMean](/data.go?s=1477:1529#L43)
``` go
func (f Float64Data) HarmonicMean() (float64, error)
```
-HarmonicMean returns the mode of the data
+HarmonicMean returns the harmonic mean of the data
+
+
+
+
+### func (Float64Data) [Histogram](/histogram.go?s=1359:1425#L55)
+``` go
+func (f Float64Data) Histogram(bins int) ([]int, []float64, error)
+```
+Histogram returns the counts and equal-width bin edges of the data
-### func (Float64Data) [InterQuartileRange](/data.go?s=3755:3813#L106)
+### func (Float64Data) [InterQuartileRange](/data.go?s=3950:4008#L111)
``` go
func (f Float64Data) InterQuartileRange() (float64, error)
```
@@ -997,6 +1666,25 @@ InterQuartileRange finds the range between Q1 and Q3
+### func (Float64Data) [KendallTau](/kendall.go?s=1384:1447#L55)
+``` go
+func (f Float64Data) KendallTau(d Float64Data) (float64, error)
+```
+KendallTau calculates Kendall's tau-b rank correlation coefficient
+between two variables.
+
+
+
+
+### func (Float64Data) [Kurtosis](/kurtosis.go?s=1501:1549#L58)
+``` go
+func (f Float64Data) Kurtosis() (float64, error)
+```
+Kurtosis finds the population excess kurtosis of a slice of floats
+
+
+
+
### func (Float64Data) [Len](/data.go?s=217:247#L10)
``` go
func (f Float64Data) Len() int
@@ -1042,7 +1730,7 @@ Median returns the median of the data
-### func (Float64Data) [MedianAbsoluteDeviation](/data.go?s=1630:1693#L46)
+### func (Float64Data) [MedianAbsoluteDeviation](/data.go?s=1647:1710#L46)
``` go
func (f Float64Data) MedianAbsoluteDeviation() (float64, error)
```
@@ -1051,7 +1739,7 @@ MedianAbsoluteDeviation the median of the absolute deviations from the dataset m
-### func (Float64Data) [MedianAbsoluteDeviationPopulation](/data.go?s=1842:1915#L51)
+### func (Float64Data) [MedianAbsoluteDeviationPopulation](/data.go?s=1859:1932#L51)
``` go
func (f Float64Data) MedianAbsoluteDeviationPopulation() (float64, error)
```
@@ -1060,7 +1748,7 @@ MedianAbsoluteDeviationPopulation finds the median of the absolute deviations fr
-### func (Float64Data) [Midhinge](/data.go?s=3912:3973#L111)
+### func (Float64Data) [Midhinge](/data.go?s=4107:4168#L116)
``` go
func (f Float64Data) Midhinge(d Float64Data) (float64, error)
```
@@ -1087,7 +1775,61 @@ Mode returns the mode of the data
-### func (Float64Data) [Pearson](/data.go?s=3455:3515#L96)
+### func (Float64Data) [MovingAverage](/rolling.go?s=1768:1833#L58)
+``` go
+func (f Float64Data) MovingAverage(window int) ([]float64, error)
+```
+MovingAverage returns the rolling mean of the data over a trailing window
+
+
+
+
+### func (Float64Data) [MovingMax](/moving.go?s=3475:3536#L118)
+``` go
+func (f Float64Data) MovingMax(window int) ([]float64, error)
+```
+MovingMax returns the rolling maximum of the data over a trailing window
+
+
+
+
+### func (Float64Data) [MovingMedian](/moving.go?s=3125:3189#L108)
+``` go
+func (f Float64Data) MovingMedian(window int) ([]float64, error)
+```
+MovingMedian returns the rolling median of the data over a trailing window
+
+
+
+
+### func (Float64Data) [MovingMin](/moving.go?s=3303:3364#L113)
+``` go
+func (f Float64Data) MovingMin(window int) ([]float64, error)
+```
+MovingMin returns the rolling minimum of the data over a trailing window
+
+
+
+
+### func (Float64Data) [MovingStdDev](/rolling.go?s=1969:2033#L63)
+``` go
+func (f Float64Data) MovingStdDev(window int) ([]float64, error)
+```
+MovingStdDev returns the rolling sample standard deviation of the data over a trailing window
+
+
+
+
+### func (Float64Data) [MovingSum](/moving.go?s=3643:3704#L123)
+``` go
+func (f Float64Data) MovingSum(window int) ([]float64, error)
+```
+MovingSum returns the rolling sum of the data over a trailing window
+
+
+
+
+### func (Float64Data) [Pearson](/data.go?s=3472:3532#L96)
``` go
func (f Float64Data) Pearson(d Float64Data) (float64, error)
```
@@ -1096,7 +1838,16 @@ Pearson calculates the Pearson product-moment correlation coefficient between tw
-### func (Float64Data) [Percentile](/data.go?s=2696:2755#L76)
+### func (Float64Data) [PercentChange](/diff.go?s=1374:1429#L48)
+``` go
+func (f Float64Data) PercentChange() ([]float64, error)
+```
+PercentChange returns the fractional change between successive elements of the data
+
+
+
+
+### func (Float64Data) [Percentile](/data.go?s=2713:2772#L76)
``` go
func (f Float64Data) Percentile(p float64) (float64, error)
```
@@ -1105,7 +1856,7 @@ Percentile finds the relative standing in a slice of floats
-### func (Float64Data) [PercentileNearestRank](/data.go?s=2869:2939#L81)
+### func (Float64Data) [PercentileNearestRank](/data.go?s=2886:2956#L81)
``` go
func (f Float64Data) PercentileNearestRank(p float64) (float64, error)
```
@@ -1114,7 +1865,25 @@ PercentileNearestRank finds the relative standing using the Nearest Rank method
-### func (Float64Data) [PopulationVariance](/data.go?s=4495:4553#L131)
+### func (Float64Data) [PercentileOfScore](/percentile_of_score.go?s=786:856#L29)
+``` go
+func (f Float64Data) PercentileOfScore(score float64) (float64, error)
+```
+PercentileOfScore calculates the percentile rank of a score relative to the data
+
+
+
+
+### func (Float64Data) [PopulationKurtosis](/kurtosis.go?s=1655:1713#L63)
+``` go
+func (f Float64Data) PopulationKurtosis() (float64, error)
+```
+PopulationKurtosis finds the population excess kurtosis of a slice of floats
+
+
+
+
+### func (Float64Data) [PopulationVariance](/data.go?s=4690:4748#L136)
``` go
func (f Float64Data) PopulationVariance() (float64, error)
```
@@ -1123,7 +1892,16 @@ PopulationVariance finds the amount of variance within a population
-### func (Float64Data) [Quartile](/data.go?s=3610:3673#L101)
+### func (Float64Data) [Product](/product.go?s=544:591#L24)
+``` go
+func (f Float64Data) Product() (float64, error)
+```
+Product calculates the product of the data
+
+
+
+
+### func (Float64Data) [Quartile](/data.go?s=3805:3868#L106)
``` go
func (f Float64Data) Quartile(d Float64Data) (Quartiles, error)
```
@@ -1132,7 +1910,7 @@ Quartile returns the three quartile points from a slice of data
-### func (Float64Data) [QuartileOutliers](/data.go?s=2542:2599#L71)
+### func (Float64Data) [QuartileOutliers](/data.go?s=2559:2616#L71)
``` go
func (f Float64Data) QuartileOutliers() (Outliers, error)
```
@@ -1141,7 +1919,7 @@ QuartileOutliers finds the mild and extreme outliers
-### func (Float64Data) [Quartiles](/data.go?s=5628:5679#L167)
+### func (Float64Data) [Quartiles](/data.go?s=5823:5874#L172)
``` go
func (f Float64Data) Quartiles() (Quartiles, error)
```
@@ -1150,7 +1928,53 @@ Quartiles returns the three quartile points from instance of Float64Data
-### func (Float64Data) [Sample](/data.go?s=4208:4269#L121)
+### func (Float64Data) [RMS](/rms.go?s=454:497#L21)
+``` go
+func (f Float64Data) RMS() (float64, error)
+```
+RMS calculates the root mean square of the data
+
+
+
+
+### func (Float64Data) [Range](/extremes.go?s=1795:1840#L72)
+``` go
+func (f Float64Data) Range() (float64, error)
+```
+Range returns the difference between the highest and lowest numbers in the data
+
+
+
+
+### func (Float64Data) [Rank](/rank.go?s=382:428#L14)
+``` go
+func (f Float64Data) Rank() ([]float64, error)
+```
+Rank assigns fractional (average) ranks to the input values
+
+
+
+
+### func (Float64Data) [Rescale](/rescale.go?s=603:652#L27)
+``` go
+func (f Float64Data) Rescale() ([]float64, error)
+```
+Rescale normalizes the input values to the range of 0 to 1
+by subtracting the minimum and dividing by the range
+
+
+
+
+### func (Float64Data) [SEM](/sem.go?s=625:668#L22)
+``` go
+func (f Float64Data) SEM() (float64, error)
+```
+SEM calculates the standard error of the mean of the data
+
+
+
+
+### func (Float64Data) [Sample](/data.go?s=4403:4464#L126)
``` go
func (f Float64Data) Sample(n int, r bool) ([]float64, error)
```
@@ -1159,7 +1983,16 @@ Sample returns sample from input with replacement or without
-### func (Float64Data) [SampleVariance](/data.go?s=4652:4706#L136)
+### func (Float64Data) [SampleKurtosis](/kurtosis.go?s=1836:1890#L68)
+``` go
+func (f Float64Data) SampleKurtosis() (float64, error)
+```
+SampleKurtosis finds the bias-corrected sample excess kurtosis of a slice of floats
+
+
+
+
+### func (Float64Data) [SampleVariance](/data.go?s=4847:4901#L141)
``` go
func (f Float64Data) SampleVariance() (float64, error)
```
@@ -1168,7 +2001,7 @@ SampleVariance finds the amount of variance within a sample
-### func (Float64Data) [Sigmoid](/data.go?s=5169:5218#L151)
+### func (Float64Data) [Sigmoid](/data.go?s=5364:5413#L156)
``` go
func (f Float64Data) Sigmoid() ([]float64, error)
```
@@ -1177,7 +2010,7 @@ Sigmoid returns the input values along the sigmoid or s-shaped curve
-### func (Float64Data) [SoftMax](/data.go?s=5359:5408#L157)
+### func (Float64Data) [SoftMax](/data.go?s=5554:5603#L162)
``` go
func (f Float64Data) SoftMax() ([]float64, error)
```
@@ -1187,7 +2020,16 @@ with sum of all the probabilities being equal to one.
-### func (Float64Data) [StandardDeviation](/data.go?s=2026:2083#L56)
+### func (Float64Data) [Spearman](/data.go?s=3648:3709#L101)
+``` go
+func (f Float64Data) Spearman(d Float64Data) (float64, error)
+```
+Spearman calculates the Spearman rank correlation coefficient between two variables.
+
+
+
+
+### func (Float64Data) [StandardDeviation](/data.go?s=2043:2100#L56)
``` go
func (f Float64Data) StandardDeviation() (float64, error)
```
@@ -1196,7 +2038,7 @@ StandardDeviation the amount of variation in the dataset
-### func (Float64Data) [StandardDeviationPopulation](/data.go?s=2199:2266#L61)
+### func (Float64Data) [StandardDeviationPopulation](/data.go?s=2216:2283#L61)
``` go
func (f Float64Data) StandardDeviationPopulation() (float64, error)
```
@@ -1205,7 +2047,7 @@ StandardDeviationPopulation finds the amount of variation from the population
-### func (Float64Data) [StandardDeviationSample](/data.go?s=2382:2445#L66)
+### func (Float64Data) [StandardDeviationSample](/data.go?s=2399:2462#L66)
``` go
func (f Float64Data) StandardDeviationSample() (float64, error)
```
@@ -1232,7 +2074,7 @@ Swap switches out two numbers in slice
-### func (Float64Data) [Trimean](/data.go?s=4059:4119#L116)
+### func (Float64Data) [Trimean](/data.go?s=4254:4314#L121)
``` go
func (f Float64Data) Trimean(d Float64Data) (float64, error)
```
@@ -1241,7 +2083,17 @@ Trimean finds the average of the median and the midhinge
-### func (Float64Data) [Variance](/data.go?s=4350:4398#L126)
+### func (Float64Data) [TrimmedMean](/trimmed_mean.go?s=1132:1198#L36)
+``` go
+func (f Float64Data) TrimmedMean(percent float64) (float64, error)
+```
+TrimmedMean finds the mean of the data after removing a fraction of
+the smallest and largest values from each tail
+
+
+
+
+### func (Float64Data) [Variance](/data.go?s=4545:4593#L131)
``` go
func (f Float64Data) Variance() (float64, error)
```
@@ -1250,6 +2102,35 @@ Variance the amount of variation in the dataset
+### func (Float64Data) [WeightedMean](/weighted_mean.go?s=976:1047#L40)
+``` go
+func (f Float64Data) WeightedMean(weights Float64Data) (float64, error)
+```
+WeightedMean finds the weighted mean of the data using the given weights
+
+
+
+
+### func (Float64Data) [Winsorize](/winsorize.go?s=1319:1385#L48)
+``` go
+func (f Float64Data) Winsorize(percent float64) ([]float64, error)
+```
+Winsorize returns a copy of the data with a fraction of the smallest
+and largest values in each tail clamped
+
+
+
+
+### func (Float64Data) [ZScore](/zscore.go?s=632:680#L27)
+``` go
+func (f Float64Data) ZScore() ([]float64, error)
+```
+ZScore standardizes the input values by subtracting the mean
+and dividing by the sample standard deviation
+
+
+
+
## type [Outliers](/outlier.go?s=73:139#L4)
``` go
type Outliers struct {
@@ -1315,7 +2196,7 @@ Series is a container for a series of data
-### func [ExponentialRegression](/regression.go?s=1089:1157#L50)
+### func [ExponentialRegression](/regression.go?s=1061:1129#L49)
``` go
func ExponentialRegression(s Series) (regressions Series, err error)
```
@@ -1329,7 +2210,7 @@ func LinearRegression(s Series) (regressions Series, err error)
LinearRegression finds the least squares linear regression on data series
-### func [LogarithmicRegression](/regression.go?s=1903:1971#L85)
+### func [LogarithmicRegression](/regression.go?s=1875:1943#L84)
``` go
func LogarithmicRegression(s Series) (regressions Series, err error)
```
diff --git a/vendor/github.com/montanaflynn/stats/Makefile b/vendor/github.com/montanaflynn/stats/Makefile
index 969df12..dfa95a6 100644
--- a/vendor/github.com/montanaflynn/stats/Makefile
+++ b/vendor/github.com/montanaflynn/stats/Makefile
@@ -24,11 +24,10 @@ docs:
godoc2md github.com/montanaflynn/stats | sed -e s#src/target/##g > DOCUMENTATION.md
release:
- git-chglog --output CHANGELOG.md --next-tag ${TAG}
+ @test -n "${TAG}" || { echo "TAG is required, e.g. make release TAG=v0.10.0"; exit 1; }
+ sh scripts/update-changelog.sh ${TAG}
git add CHANGELOG.md
- git commit -m "Update changelog with ${TAG} changes"
- git tag ${TAG}
- git-chglog $(TAG) | tail -n +4 | gsed '1s/^/$(TAG)\n/gm' > release-notes.txt
+ git commit -m "chore: update changelog for ${TAG}"
+ git tag -a ${TAG} -m "${TAG}"
git push origin master ${TAG}
- hub release create --copy -F release-notes.txt ${TAG}
diff --git a/vendor/github.com/montanaflynn/stats/README.md b/vendor/github.com/montanaflynn/stats/README.md
index 1cd4895..c91d25f 100644
--- a/vendor/github.com/montanaflynn/stats/README.md
+++ b/vendor/github.com/montanaflynn/stats/README.md
@@ -1,6 +1,6 @@
# Stats - Golang Statistics Package
-[![][action-svg]][action-url] [![][codecov-svg]][codecov-url] [![][goreport-svg]][goreport-url] [![][godoc-svg]][godoc-url] [![][pkggodev-svg]][pkggodev-url] [![][license-svg]][license-url]
+[![][action-svg]][action-url] [![][codecov-svg]][codecov-url] [![][godoc-svg]][godoc-url] [![][pkggodev-svg]][pkggodev-url] [![][license-svg]][license-url]
A well tested and comprehensive Golang statistics library / package / module with no dependencies.
@@ -14,7 +14,7 @@ go get github.com/montanaflynn/stats
## Example Usage
-All the functions can be seen in [examples/main.go](examples/main.go) but here's a little taste:
+All the functions can be seen in [examples/functions/main.go](examples/functions/main.go) but here's a little taste:
```go
// start with some source data to use
@@ -70,19 +70,32 @@ type Float64Data []float64
func LoadRawData(raw interface{}) (f Float64Data) {}
+func ArgMax(input Float64Data) (int, error) {}
+func ArgMin(input Float64Data) (int, error) {}
func AutoCorrelation(data Float64Data, lags int) (float64, error) {}
func ChebyshevDistance(dataPointX, dataPointY Float64Data) (distance float64, err error) {}
+func Clip(input Float64Data, min, max float64) ([]float64, error) {}
+func CoefficientOfVariation(input Float64Data) (float64, error) {}
func Correlation(data1, data2 Float64Data) (float64, error) {}
func Covariance(data1, data2 Float64Data) (float64, error) {}
func CovariancePopulation(data1, data2 Float64Data) (float64, error) {}
+func CumulativeMax(input Float64Data) ([]float64, error) {}
+func CumulativeMin(input Float64Data) ([]float64, error) {}
+func CumulativeProduct(input Float64Data) ([]float64, error) {}
func CumulativeSum(input Float64Data) ([]float64, error) {}
func Describe(input Float64Data, allowNaN bool, percentiles *[]float64) (*Description, error) {}
func DescribePercentileFunc(input Float64Data, allowNaN bool, percentiles *[]float64, percentileFunc func(Float64Data, float64) (float64, error)) (*Description, error) {}
+func Diff(input Float64Data) ([]float64, error) {}
+func EWMA(input Float64Data, alpha float64) ([]float64, error) {}
func Entropy(input Float64Data) (float64, error) {}
func EuclideanDistance(dataPointX, dataPointY Float64Data) (distance float64, err error) {}
func GeometricMean(input Float64Data) (float64, error) {}
func HarmonicMean(input Float64Data) (float64, error) {}
+func Histogram(input Float64Data, bins int) ([]int, []float64, error) {}
func InterQuartileRange(input Float64Data) (float64, error) {}
+func Interp(x, xp, fp Float64Data) ([]float64, error) {}
+func KendallTau(data1, data2 Float64Data) (float64, error) {}
+func Kurtosis(input Float64Data) (float64, error) {}
func ManhattanDistance(dataPointX, dataPointY Float64Data) (distance float64, err error) {}
func Max(input Float64Data) (max float64, err error) {}
func Mean(input Float64Data) (float64, error) {}
@@ -93,6 +106,12 @@ func Midhinge(input Float64Data) (float64, error) {}
func Min(input Float64Data) (min float64, err error) {}
func MinkowskiDistance(dataPointX, dataPointY Float64Data, lambda float64) (distance float64, err error) {}
func Mode(input Float64Data) (mode []float64, err error) {}
+func MovingAverage(input Float64Data, window int) ([]float64, error) {}
+func MovingMax(input Float64Data, window int) ([]float64, error) {}
+func MovingMedian(input Float64Data, window int) ([]float64, error) {}
+func MovingMin(input Float64Data, window int) ([]float64, error) {}
+func MovingStdDev(input Float64Data, window int) ([]float64, error) {}
+func MovingSum(input Float64Data, window int) ([]float64, error) {}
func NormBoxMullerRvs(loc float64, scale float64, size int) []float64 {}
func NormCdf(x float64, loc float64, scale float64) float64 {}
func NormEntropy(loc float64, scale float64) float64 {}
@@ -107,20 +126,33 @@ func NormMedian(loc float64, scale float64) float64 {}
func NormMoment(n int, loc float64, scale float64) float64 {}
func NormPdf(x float64, loc float64, scale float64) float64 {}
func NormPpf(p float64, loc float64, scale float64) (x float64) {}
+func NormSample(loc float64, scale float64, size int) []float64 {}
func NormPpfRvs(loc float64, scale float64, size int) []float64 {}
func NormSf(x float64, loc float64, scale float64) float64 {}
func NormStats(loc float64, scale float64, moments string) []float64 {}
func NormStd(loc float64, scale float64) float64 {}
func NormVar(loc float64, scale float64) float64 {}
func Pearson(data1, data2 Float64Data) (float64, error) {}
+func PercentChange(input Float64Data) ([]float64, error) {}
func Percentile(input Float64Data, percent float64) (percentile float64, err error) {}
func PercentileNearestRank(input Float64Data, percent float64) (percentile float64, err error) {}
+func PercentileOfScore(input Float64Data, score float64) (float64, error) {}
+func PercentileWeighted(data, weights Float64Data, percent float64) (percentile float64, err error) {}
+func PopulationKurtosis(input Float64Data) (float64, error) {}
func PopulationSkewness(input Float64Data) (float64, error) {}
func PopulationVariance(input Float64Data) (pvar float64, err error) {}
+func Product(input Float64Data) (float64, error) {}
+func RMS(input Float64Data) (float64, error) {}
+func Range(input Float64Data) (float64, error) {}
+func Rank(input Float64Data) ([]float64, error) {}
+func Rescale(input Float64Data) ([]float64, error) {}
+func SEM(input Float64Data) (float64, error) {}
func Sample(input Float64Data, takenum int, replacement bool) ([]float64, error) {}
+func SampleKurtosis(input Float64Data) (float64, error) {}
func SampleSkewness(input Float64Data) (float64, error) {}
func SampleVariance(input Float64Data) (svar float64, err error) {}
func Skewness(input Float64Data) (float64, error) {}
+func Spearman(data1, data2 Float64Data) (float64, error) {}
func Sigmoid(input Float64Data) ([]float64, error) {}
func SoftMax(input Float64Data) ([]float64, error) {}
func StableSample(input Float64Data, takenum int) ([]float64, error) {}
@@ -130,10 +162,16 @@ func StandardDeviationSample(input Float64Data) (sdev float64, err error) {}
func StdDevP(input Float64Data) (sdev float64, err error) {}
func StdDevS(input Float64Data) (sdev float64, err error) {}
func Sum(input Float64Data) (sum float64, err error) {}
+func TTest(data1, data2 Float64Data, populationMean float64) (t float64, pvalue float64, err error) {}
func Trimean(input Float64Data) (float64, error) {}
+func TrimmedMean(input Float64Data, percent float64) (float64, error) {}
func VarP(input Float64Data) (sdev float64, err error) {}
func VarS(input Float64Data) (sdev float64, err error) {}
func Variance(input Float64Data) (sdev float64, err error) {}
+func WeightedMean(data, weights Float64Data) (float64, error) {}
+func Winsorize(input Float64Data, percent float64) ([]float64, error) {}
+func ZScore(input Float64Data) ([]float64, error) {}
+func ZTest(data1, data2 Float64Data, populationMean, populationStdDev float64) (z float64, pvalue float64, err error) {}
func ProbGeom(a int, b int, p float64) (prob float64, err error) {}
func ExpGeom(p float64) (exp float64, err error) {}
func VarGeom(p float64) (exp float64, err error) {}
@@ -178,7 +216,7 @@ Pull request are always welcome no matter how big or small. I've included a [Mak
To make things as seamless as possible please also consider the following steps:
-- Update `examples/main.go` with a simple example of the new feature
+- Update `examples/functions/main.go` with a simple example of the new feature
- Update `README.md` documentation section with any new exported API
- Keep 100% code coverage (you can check with `make coverage`)
- Squash commits into single units of work with `git rebase -i new-feature`
@@ -208,9 +246,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
[codecov-url]: https://app.codecov.io/gh/montanaflynn/stats
[codecov-svg]: https://img.shields.io/codecov/c/github/montanaflynn/stats?token=wnw8dActnH
-[goreport-url]: https://goreportcard.com/report/github.com/montanaflynn/stats
-[goreport-svg]: https://goreportcard.com/badge/github.com/montanaflynn/stats
-
[godoc-url]: https://godoc.org/github.com/montanaflynn/stats
[godoc-svg]: https://godoc.org/github.com/montanaflynn/stats?status.svg
diff --git a/vendor/github.com/montanaflynn/stats/clip.go b/vendor/github.com/montanaflynn/stats/clip.go
new file mode 100644
index 0000000..94b625a
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/clip.go
@@ -0,0 +1,32 @@
+package stats
+
+// Clip clamps each value in the input slice into the
+// inclusive range between min and max.
+func Clip(input Float64Data, min, max float64) ([]float64, error) {
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ if min > max {
+ return nil, ErrBounds
+ }
+
+ c := make([]float64, len(input))
+ for i, v := range input {
+ switch {
+ case v < min:
+ c[i] = min
+ case v > max:
+ c[i] = max
+ default:
+ c[i] = v
+ }
+ }
+ return c, nil
+}
+
+// Clip clamps each value in the input slice into the
+// inclusive range between min and max.
+func (f Float64Data) Clip(min, max float64) ([]float64, error) {
+ return Clip(f, min, max)
+}
diff --git a/vendor/github.com/montanaflynn/stats/coefficient_of_variation.go b/vendor/github.com/montanaflynn/stats/coefficient_of_variation.go
new file mode 100644
index 0000000..25789cd
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/coefficient_of_variation.go
@@ -0,0 +1,31 @@
+package stats
+
+import "math"
+
+// CoefficientOfVariation finds the coefficient of variation of a slice
+// of floats, defined as the sample standard deviation divided by the
+// mean. This matches the behavior of Python's scipy.stats.variation
+// with ddof=1.
+//
+// The input must not be empty and its mean must not be zero.
+func CoefficientOfVariation(input Float64Data) (float64, error) {
+ if input.Len() == 0 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ // Input is known to be non-empty so the mean and sample
+ // standard deviation cannot return an error
+ m, _ := Mean(input)
+ if m == 0 {
+ return math.NaN(), ErrZero
+ }
+
+ sd, _ := StandardDeviationSample(input)
+
+ return sd / m, nil
+}
+
+// CoefficientOfVariation finds the sample standard deviation divided by the mean
+func (f Float64Data) CoefficientOfVariation() (float64, error) {
+ return CoefficientOfVariation(f)
+}
diff --git a/vendor/github.com/montanaflynn/stats/correlation.go b/vendor/github.com/montanaflynn/stats/correlation.go
index 4acab94..1289063 100644
--- a/vendor/github.com/montanaflynn/stats/correlation.go
+++ b/vendor/github.com/montanaflynn/stats/correlation.go
@@ -2,6 +2,7 @@ package stats
import (
"math"
+ "sort"
)
// Correlation describes the degree of relationship between two sets of data
@@ -34,27 +35,95 @@ func Pearson(data1, data2 Float64Data) (float64, error) {
return Correlation(data1, data2)
}
+// Spearman calculates the Spearman rank correlation coefficient between two variables.
+// It works by ranking the data and then computing the Pearson correlation of the ranks.
+// This method handles tied values using fractional (average) ranking.
+func Spearman(data1, data2 Float64Data) (float64, error) {
+
+ l1 := data1.Len()
+ l2 := data2.Len()
+
+ if l1 == 0 || l2 == 0 {
+ return math.NaN(), EmptyInputErr
+ }
+
+ if l1 != l2 {
+ return math.NaN(), SizeErr
+ }
+
+ ranks1 := rankData(data1)
+ ranks2 := rankData(data2)
+
+ return Correlation(ranks1, ranks2)
+}
+
+// rankData assigns fractional (average) ranks to the data values.
+// Tied values receive the average of the ranks they would have been assigned.
+func rankData(data Float64Data) Float64Data {
+ n := len(data)
+
+ // Create index-value pairs and sort by value
+ type indexedValue struct {
+ index int
+ value float64
+ }
+
+ sorted := make([]indexedValue, n)
+ for i, v := range data {
+ sorted[i] = indexedValue{i, v}
+ }
+
+ sort.SliceStable(sorted, func(i, j int) bool {
+ return sorted[i].value < sorted[j].value
+ })
+
+ ranks := make(Float64Data, n)
+
+ // Assign fractional ranks handling ties
+ for i := 0; i < n; {
+ j := i + 1
+ for j < n && sorted[j].value == sorted[i].value {
+ j++
+ }
+
+ // Average rank for tied values (ranks are 1-based)
+ avgRank := float64(i+j+1) / 2.0
+ for k := i; k < j; k++ {
+ ranks[sorted[k].index] = avgRank
+ }
+
+ i = j
+ }
+
+ return ranks
+}
+
// AutoCorrelation is the correlation of a signal with a delayed copy of itself as a function of delay
func AutoCorrelation(data Float64Data, lags int) (float64, error) {
if len(data) < 1 {
return 0, EmptyInputErr
}
+ if lags < 0 || lags >= len(data) {
+ return 0, BoundsErr
+ }
+
mean, _ := Mean(data)
- var result, q float64
+ var variance float64
+ for _, v := range data {
+ delta := v - mean
+ variance += delta * delta
+ }
- for i := 0; i < lags; i++ {
- v := (data[0] - mean) * (data[0] - mean)
- for i := 1; i < len(data); i++ {
- delta0 := data[i-1] - mean
- delta1 := data[i] - mean
- q += (delta0*delta1 - q) / float64(i+1)
- v += (delta1*delta1 - v) / float64(i+1)
- }
+ if variance == 0 {
+ return 0, nil
+ }
- result = q / v
+ var covariance float64
+ for i := lags; i < len(data); i++ {
+ covariance += (data[i] - mean) * (data[i-lags] - mean)
}
- return result, nil
+ return covariance / variance, nil
}
diff --git a/vendor/github.com/montanaflynn/stats/cumulative.go b/vendor/github.com/montanaflynn/stats/cumulative.go
new file mode 100644
index 0000000..897f827
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/cumulative.go
@@ -0,0 +1,76 @@
+package stats
+
+// CumulativeProduct calculates the cumulative product of the input slice
+func CumulativeProduct(input Float64Data) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return Float64Data{}, ErrEmptyInput
+ }
+
+ cumProduct := make([]float64, input.Len())
+
+ for i, val := range input {
+ if i == 0 {
+ cumProduct[i] = val
+ } else {
+ cumProduct[i] = cumProduct[i-1] * val
+ }
+ }
+
+ return cumProduct, nil
+}
+
+// CumulativeMax calculates the cumulative maximum of the input slice
+func CumulativeMax(input Float64Data) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return Float64Data{}, ErrEmptyInput
+ }
+
+ cumMax := make([]float64, input.Len())
+
+ for i, val := range input {
+ if i == 0 || val > cumMax[i-1] {
+ cumMax[i] = val
+ } else {
+ cumMax[i] = cumMax[i-1]
+ }
+ }
+
+ return cumMax, nil
+}
+
+// CumulativeMin calculates the cumulative minimum of the input slice
+func CumulativeMin(input Float64Data) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return Float64Data{}, ErrEmptyInput
+ }
+
+ cumMin := make([]float64, input.Len())
+
+ for i, val := range input {
+ if i == 0 || val < cumMin[i-1] {
+ cumMin[i] = val
+ } else {
+ cumMin[i] = cumMin[i-1]
+ }
+ }
+
+ return cumMin, nil
+}
+
+// CumulativeProduct calculates the cumulative product of the data
+func (f Float64Data) CumulativeProduct() ([]float64, error) {
+ return CumulativeProduct(f)
+}
+
+// CumulativeMax calculates the cumulative maximum of the data
+func (f Float64Data) CumulativeMax() ([]float64, error) {
+ return CumulativeMax(f)
+}
+
+// CumulativeMin calculates the cumulative minimum of the data
+func (f Float64Data) CumulativeMin() ([]float64, error) {
+ return CumulativeMin(f)
+}
diff --git a/vendor/github.com/montanaflynn/stats/data.go b/vendor/github.com/montanaflynn/stats/data.go
index b86f0d8..1e249b9 100644
--- a/vendor/github.com/montanaflynn/stats/data.go
+++ b/vendor/github.com/montanaflynn/stats/data.go
@@ -36,10 +36,10 @@ func (f Float64Data) Median() (float64, error) { return Median(f) }
// Mode returns the mode of the data
func (f Float64Data) Mode() ([]float64, error) { return Mode(f) }
-// GeometricMean returns the median of the data
+// GeometricMean returns the geometric mean of the data
func (f Float64Data) GeometricMean() (float64, error) { return GeometricMean(f) }
-// HarmonicMean returns the mode of the data
+// HarmonicMean returns the harmonic mean of the data
func (f Float64Data) HarmonicMean() (float64, error) { return HarmonicMean(f) }
// MedianAbsoluteDeviation the median of the absolute deviations from the dataset median
@@ -97,6 +97,11 @@ func (f Float64Data) Pearson(d Float64Data) (float64, error) {
return Pearson(f, d)
}
+// Spearman calculates the Spearman rank correlation coefficient between two variables.
+func (f Float64Data) Spearman(d Float64Data) (float64, error) {
+ return Spearman(f, d)
+}
+
// Quartile returns the three quartile points from a slice of data
func (f Float64Data) Quartile(d Float64Data) (Quartiles, error) {
return Quartile(d)
diff --git a/vendor/github.com/montanaflynn/stats/describe.go b/vendor/github.com/montanaflynn/stats/describe.go
index 86b7242..3904ac0 100644
--- a/vendor/github.com/montanaflynn/stats/describe.go
+++ b/vendor/github.com/montanaflynn/stats/describe.go
@@ -9,6 +9,7 @@ type Description struct {
Std float64
Max float64
Min float64
+ Range float64
DescriptionPercentiles []descriptionPercentile
AllowedNaN bool
}
@@ -39,6 +40,7 @@ func DescribePercentileFunc(input Float64Data, allowNaN bool, percentiles *[]flo
description.Std, _ = StandardDeviation(input)
description.Max, _ = Max(input)
description.Min, _ = Min(input)
+ description.Range, _ = Range(input)
description.Mean, _ = Mean(input)
if percentiles != nil {
@@ -60,6 +62,7 @@ Represents the Description instance in a string format with specified number of
std 0.82
max 3.00
min 1.00
+ range 2.00
25.00% NaN
50.00% 1.50
75.00% 2.50
@@ -73,6 +76,7 @@ func (d *Description) String(decimals int) string {
str += fmt.Sprintf("std\t%.*f\n", decimals, d.Std)
str += fmt.Sprintf("max\t%.*f\n", decimals, d.Max)
str += fmt.Sprintf("min\t%.*f\n", decimals, d.Min)
+ str += fmt.Sprintf("range\t%.*f\n", decimals, d.Range)
for _, percentile := range d.DescriptionPercentiles {
str += fmt.Sprintf("%.2f%%\t%.*f\n", percentile.Percentile, decimals, percentile.Value)
}
diff --git a/vendor/github.com/montanaflynn/stats/diff.go b/vendor/github.com/montanaflynn/stats/diff.go
new file mode 100644
index 0000000..7a9bdfc
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/diff.go
@@ -0,0 +1,48 @@
+package stats
+
+// Diff calculates the successive differences of the input slice,
+// returning input[i] - input[i-1] for each i in 1..len(input)-1.
+// The output has length len(input) - 1; a single-element input
+// returns an empty slice.
+func Diff(input Float64Data) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ diff := make([]float64, input.Len()-1)
+
+ for i := 1; i < input.Len(); i++ {
+ diff[i-1] = input[i] - input[i-1]
+ }
+
+ return diff, nil
+}
+
+// PercentChange calculates the fractional change between successive
+// elements of the input slice, returning
+// (input[i] - input[i-1]) / input[i-1] for each i in 1..len(input)-1.
+// The output has length len(input) - 1; a single-element input
+// returns an empty slice. A zero denominator follows IEEE 754
+// semantics, yielding +Inf, -Inf, or NaN (for 0/0), matching the
+// behavior of pandas pct_change.
+func PercentChange(input Float64Data) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ change := make([]float64, input.Len()-1)
+
+ for i := 1; i < input.Len(); i++ {
+ change[i-1] = (input[i] - input[i-1]) / input[i-1]
+ }
+
+ return change, nil
+}
+
+// Diff returns the successive differences of the data
+func (f Float64Data) Diff() ([]float64, error) { return Diff(f) }
+
+// PercentChange returns the fractional change between successive elements of the data
+func (f Float64Data) PercentChange() ([]float64, error) { return PercentChange(f) }
diff --git a/vendor/github.com/montanaflynn/stats/ewma.go b/vendor/github.com/montanaflynn/stats/ewma.go
new file mode 100644
index 0000000..a0b59a5
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/ewma.go
@@ -0,0 +1,32 @@
+package stats
+
+// EWMA calculates the exponentially weighted moving average of the input
+// with smoothing factor alpha. The first output equals the first input and
+// each subsequent entry is alpha*input[i] + (1-alpha)*output[i-1], so the
+// result has the same length as the input. The alpha must satisfy
+// 0 < alpha <= 1 or ErrBounds is returned. An empty input returns
+// ErrEmptyInput.
+func EWMA(input Float64Data, alpha float64) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ if alpha <= 0 || alpha > 1 {
+ return nil, ErrBounds
+ }
+
+ output := make([]float64, input.Len())
+
+ output[0] = input[0]
+ for i := 1; i < input.Len(); i++ {
+ output[i] = alpha*input[i] + (1-alpha)*output[i-1]
+ }
+
+ return output, nil
+}
+
+// EWMA returns the exponentially weighted moving average of the data with smoothing factor alpha
+func (f Float64Data) EWMA(alpha float64) ([]float64, error) {
+ return EWMA(f, alpha)
+}
diff --git a/vendor/github.com/montanaflynn/stats/extremes.go b/vendor/github.com/montanaflynn/stats/extremes.go
new file mode 100644
index 0000000..dd31581
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/extremes.go
@@ -0,0 +1,72 @@
+package stats
+
+// ArgMax finds the index of the highest number in a slice,
+// returning the first occurrence in the case of ties
+func ArgMax(input Float64Data) (int, error) {
+
+ // Return an error if there are no numbers
+ if input.Len() == 0 {
+ return -1, ErrEmptyInput
+ }
+
+ // Track the index of the highest value seen so far
+ index := 0
+
+ // Loop and replace with strictly higher values only,
+ // which keeps the first occurrence on ties
+ for i := 1; i < input.Len(); i++ {
+ if input.Get(i) > input.Get(index) {
+ index = i
+ }
+ }
+
+ return index, nil
+}
+
+// ArgMin finds the index of the lowest number in a slice,
+// returning the first occurrence in the case of ties
+func ArgMin(input Float64Data) (int, error) {
+
+ // Return an error if there are no numbers
+ if input.Len() == 0 {
+ return -1, ErrEmptyInput
+ }
+
+ // Track the index of the lowest value seen so far
+ index := 0
+
+ // Loop and replace with strictly lower values only,
+ // which keeps the first occurrence on ties
+ for i := 1; i < input.Len(); i++ {
+ if input.Get(i) < input.Get(index) {
+ index = i
+ }
+ }
+
+ return index, nil
+}
+
+// Range finds the difference between the highest and
+// lowest numbers in a slice
+func Range(input Float64Data) (float64, error) {
+
+ // Return an error if there are no numbers
+ max, err := Max(input)
+ if err != nil {
+ return max, ErrEmptyInput
+ }
+
+ // Disregard error, since Max would have already returned it
+ min, _ := Min(input)
+
+ return max - min, nil
+}
+
+// ArgMax returns the index of the highest number in the data
+func (f Float64Data) ArgMax() (int, error) { return ArgMax(f) }
+
+// ArgMin returns the index of the lowest number in the data
+func (f Float64Data) ArgMin() (int, error) { return ArgMin(f) }
+
+// Range returns the difference between the highest and lowest numbers in the data
+func (f Float64Data) Range() (float64, error) { return Range(f) }
diff --git a/vendor/github.com/montanaflynn/stats/histogram.go b/vendor/github.com/montanaflynn/stats/histogram.go
new file mode 100644
index 0000000..c2ebb8d
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/histogram.go
@@ -0,0 +1,57 @@
+package stats
+
+import "sort"
+
+// Histogram calculates the histogram of a slice using the given
+// number of equal-width bins over [min, max], returning the count
+// of values in each bin along with the bins+1 bin edges. Each bin
+// is half-open [edges[i], edges[i+1]) except the last, which also
+// includes the maximum value.
+func Histogram(input Float64Data, bins int) ([]int, []float64, error) {
+
+ if input.Len() == 0 {
+ return nil, nil, ErrEmptyInput
+ }
+
+ if bins < 1 {
+ return nil, nil, ErrBounds
+ }
+
+ // Disregard errors, since input is not empty
+ min, _ := Min(input)
+ max, _ := Max(input)
+
+ // Expand the range by 0.5 on each side like
+ // numpy when all of the values are equal
+ if min == max {
+ min -= 0.5
+ max += 0.5
+ }
+
+ // Build bins+1 equal-width bin edges from min to max
+ width := (max - min) / float64(bins)
+ edges := make([]float64, bins+1)
+ for i := range edges {
+ edges[i] = min + width*float64(i)
+ }
+ edges[bins] = max
+
+ // Count each value into the last bin whose left
+ // edge does not exceed it, so the maximum value
+ // lands in the final closed bin
+ counts := make([]int, bins)
+ for _, v := range input {
+ i := sort.Search(len(edges), func(i int) bool { return edges[i] > v }) - 1
+ if i == bins {
+ i--
+ }
+ counts[i]++
+ }
+
+ return counts, edges, nil
+}
+
+// Histogram returns the counts and equal-width bin edges of the data
+func (f Float64Data) Histogram(bins int) ([]int, []float64, error) {
+ return Histogram(f, bins)
+}
diff --git a/vendor/github.com/montanaflynn/stats/interp.go b/vendor/github.com/montanaflynn/stats/interp.go
new file mode 100644
index 0000000..86a4c3a
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/interp.go
@@ -0,0 +1,46 @@
+package stats
+
+import "sort"
+
+// Interp calculates the one-dimensional piecewise-linear interpolant to a
+// function with given discrete data points (xp, fp), evaluated at each x.
+// Values of x below xp[0] return fp[0] and values above xp[len(xp)-1] return
+// fp[len(xp)-1], so no extrapolation is performed. Unlike numpy's interp,
+// which silently returns nonsense for unsorted coordinates, xp must be
+// strictly increasing or ErrBounds is returned. An empty x or xp returns
+// ErrEmptyInput and xp and fp of different lengths return ErrSize.
+func Interp(x, xp, fp Float64Data) ([]float64, error) {
+
+ if x.Len() == 0 || xp.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ if xp.Len() != fp.Len() {
+ return nil, ErrSize
+ }
+
+ for i := 1; i < xp.Len(); i++ {
+ if xp[i] <= xp[i-1] {
+ return nil, ErrBounds
+ }
+ }
+
+ output := make([]float64, x.Len())
+
+ for i, xv := range x {
+ switch {
+ case xv <= xp[0]:
+ output[i] = fp[0]
+ case xv >= xp[xp.Len()-1]:
+ output[i] = fp[fp.Len()-1]
+ default:
+ // The first index with xp[j] >= xv, which the clamping
+ // above guarantees is within [1, len(xp)-1]
+ j := sort.SearchFloat64s(xp, xv)
+ t := (xv - xp[j-1]) / (xp[j] - xp[j-1])
+ output[i] = fp[j-1] + t*(fp[j]-fp[j-1])
+ }
+ }
+
+ return output, nil
+}
diff --git a/vendor/github.com/montanaflynn/stats/kendall.go b/vendor/github.com/montanaflynn/stats/kendall.go
new file mode 100644
index 0000000..bba7928
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/kendall.go
@@ -0,0 +1,57 @@
+package stats
+
+import "math"
+
+// KendallTau calculates Kendall's tau-b rank correlation coefficient
+// between two variables. Tau-b corrects for ties, matching the values
+// produced by SciPy's kendalltau and pandas' corr(method="kendall").
+// Pairs are compared with a simple O(n^2) loop for clarity.
+func KendallTau(data1, data2 Float64Data) (float64, error) {
+
+ l1 := data1.Len()
+ l2 := data2.Len()
+
+ if l1 == 0 || l2 == 0 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ if l1 != l2 {
+ return math.NaN(), ErrSize
+ }
+
+ // Count concordant and discordant pairs along with pairs
+ // tied only in the first or only in the second variable.
+ var concordant, discordant, tiedX, tiedY float64
+ for i := 0; i < l1; i++ {
+ for j := i + 1; j < l1; j++ {
+ dx := data1[i] - data1[j]
+ dy := data2[i] - data2[j]
+ switch {
+ case dx == 0 && dy == 0:
+ // Pairs tied in both variables are excluded
+ case dx == 0:
+ tiedX++
+ case dy == 0:
+ tiedY++
+ case (dx > 0) == (dy > 0):
+ concordant++
+ default:
+ discordant++
+ }
+ }
+ }
+
+ // tau-b = (C - D) / sqrt((C + D + Tx) * (C + D + Ty))
+ denominator := math.Sqrt((concordant + discordant + tiedX) * (concordant + discordant + tiedY))
+ if denominator == 0 {
+ return 0, nil
+ }
+
+ return (concordant - discordant) / denominator, nil
+}
+
+// KendallTau calculates Kendall's tau-b rank correlation coefficient
+// between two variables.
+func (f Float64Data) KendallTau(d Float64Data) (float64, error) {
+ return KendallTau(f, d)
+}
diff --git a/vendor/github.com/montanaflynn/stats/kurtosis.go b/vendor/github.com/montanaflynn/stats/kurtosis.go
new file mode 100644
index 0000000..4a83b20
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/kurtosis.go
@@ -0,0 +1,70 @@
+package stats
+
+import "math"
+
+// Kurtosis computes the population excess kurtosis of the dataset
+func Kurtosis(input Float64Data) (float64, error) {
+ return PopulationKurtosis(input)
+}
+
+// PopulationKurtosis computes the population excess kurtosis (Fisher
+// definition) using the fourth central moment normalized by the squared
+// variance, so a normal distribution has a kurtosis of zero.
+func PopulationKurtosis(input Float64Data) (float64, error) {
+ if input.Len() < 2 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ mean, _ := Mean(input)
+
+ // Compute sums of squared and fourth-power differences from the mean
+ var sumOfSquares, sumOfFourths float64
+ for _, v := range input {
+ d := v - mean
+ d2 := d * d
+ sumOfSquares += d2
+ sumOfFourths += d2 * d2
+ }
+
+ if sumOfSquares == 0 {
+ return math.NaN(), ErrZero
+ }
+
+ n := float64(input.Len())
+ variance := sumOfSquares / n
+
+ return (sumOfFourths/n)/(variance*variance) - 3.0, nil
+}
+
+// SampleKurtosis computes the bias-corrected sample excess kurtosis,
+// matching pandas .kurt() and scipy.stats.kurtosis with bias=False.
+func SampleKurtosis(input Float64Data) (float64, error) {
+ n := input.Len()
+ if n < 4 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ g2, err := PopulationKurtosis(input)
+ if err != nil {
+ return math.NaN(), err
+ }
+
+ // Bias-corrected: G2 = ((n+1)*g2 + 6) * (n-1) / ((n-2)*(n-3))
+ nf := float64(n)
+ return ((nf+1)*g2 + 6) * (nf - 1) / ((nf - 2) * (nf - 3)), nil
+}
+
+// Kurtosis finds the population excess kurtosis of a slice of floats
+func (f Float64Data) Kurtosis() (float64, error) {
+ return Kurtosis(f)
+}
+
+// PopulationKurtosis finds the population excess kurtosis of a slice of floats
+func (f Float64Data) PopulationKurtosis() (float64, error) {
+ return PopulationKurtosis(f)
+}
+
+// SampleKurtosis finds the bias-corrected sample excess kurtosis of a slice of floats
+func (f Float64Data) SampleKurtosis() (float64, error) {
+ return SampleKurtosis(f)
+}
diff --git a/vendor/github.com/montanaflynn/stats/mean.go b/vendor/github.com/montanaflynn/stats/mean.go
index a78d299..de4f6a6 100644
--- a/vendor/github.com/montanaflynn/stats/mean.go
+++ b/vendor/github.com/montanaflynn/stats/mean.go
@@ -22,18 +22,19 @@ func GeometricMean(input Float64Data) (float64, error) {
return math.NaN(), EmptyInputErr
}
- // Get the product of all the numbers
+ // Get the sum of all the numbers natural logs and return an
+ // error for values that cannot be included in geometric mean
var p float64
for _, n := range input {
- if p == 0 {
- p = n
- } else {
- p *= n
+ if n < 0 {
+ return math.NaN(), NegativeErr
+ } else if n == 0 {
+ return math.NaN(), ZeroErr
}
+ p += math.Log(n)
}
- // Calculate the geometric mean
- return math.Pow(p, 1/float64(l)), nil
+ return math.Exp(p / float64(l)), nil
}
// HarmonicMean gets the harmonic mean for a slice of numbers
diff --git a/vendor/github.com/montanaflynn/stats/moving.go b/vendor/github.com/montanaflynn/stats/moving.go
new file mode 100644
index 0000000..ce18f88
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/moving.go
@@ -0,0 +1,125 @@
+package stats
+
+// MovingMedian calculates the rolling median of the input over a trailing
+// window. Only fully-populated windows produce output, so the result has
+// len(input)-window+1 entries and entry i is the median of input[i : i+window].
+// The window must satisfy 1 <= window <= len(input) or ErrBounds is
+// returned. An empty input returns ErrEmptyInput.
+func MovingMedian(input Float64Data, window int) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ if window < 1 || window > input.Len() {
+ return nil, ErrBounds
+ }
+
+ output := make([]float64, input.Len()-window+1)
+
+ for i := range output {
+ // Median cannot fail here since every window is non-empty
+ median, _ := Median(input[i : i+window])
+ output[i] = median
+ }
+
+ return output, nil
+}
+
+// MovingMin calculates the rolling minimum of the input over a trailing
+// window. Only fully-populated windows produce output, so the result has
+// len(input)-window+1 entries and entry i is the minimum of
+// input[i : i+window]. The window must satisfy 1 <= window <= len(input) or
+// ErrBounds is returned. An empty input returns ErrEmptyInput.
+func MovingMin(input Float64Data, window int) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ if window < 1 || window > input.Len() {
+ return nil, ErrBounds
+ }
+
+ output := make([]float64, input.Len()-window+1)
+
+ for i := range output {
+ // Min cannot fail here since every window is non-empty
+ min, _ := Min(input[i : i+window])
+ output[i] = min
+ }
+
+ return output, nil
+}
+
+// MovingMax calculates the rolling maximum of the input over a trailing
+// window. Only fully-populated windows produce output, so the result has
+// len(input)-window+1 entries and entry i is the maximum of
+// input[i : i+window]. The window must satisfy 1 <= window <= len(input) or
+// ErrBounds is returned. An empty input returns ErrEmptyInput.
+func MovingMax(input Float64Data, window int) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ if window < 1 || window > input.Len() {
+ return nil, ErrBounds
+ }
+
+ output := make([]float64, input.Len()-window+1)
+
+ for i := range output {
+ // Max cannot fail here since every window is non-empty
+ max, _ := Max(input[i : i+window])
+ output[i] = max
+ }
+
+ return output, nil
+}
+
+// MovingSum calculates the rolling sum of the input over a trailing
+// window. Only fully-populated windows produce output, so the result has
+// len(input)-window+1 entries and entry i is the sum of input[i : i+window].
+// The window must satisfy 1 <= window <= len(input) or ErrBounds is
+// returned. An empty input returns ErrEmptyInput.
+func MovingSum(input Float64Data, window int) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ if window < 1 || window > input.Len() {
+ return nil, ErrBounds
+ }
+
+ output := make([]float64, input.Len()-window+1)
+
+ for i := range output {
+ // Sum cannot fail here since every window is non-empty
+ sum, _ := Sum(input[i : i+window])
+ output[i] = sum
+ }
+
+ return output, nil
+}
+
+// MovingMedian returns the rolling median of the data over a trailing window
+func (f Float64Data) MovingMedian(window int) ([]float64, error) {
+ return MovingMedian(f, window)
+}
+
+// MovingMin returns the rolling minimum of the data over a trailing window
+func (f Float64Data) MovingMin(window int) ([]float64, error) {
+ return MovingMin(f, window)
+}
+
+// MovingMax returns the rolling maximum of the data over a trailing window
+func (f Float64Data) MovingMax(window int) ([]float64, error) {
+ return MovingMax(f, window)
+}
+
+// MovingSum returns the rolling sum of the data over a trailing window
+func (f Float64Data) MovingSum(window int) ([]float64, error) {
+ return MovingSum(f, window)
+}
diff --git a/vendor/github.com/montanaflynn/stats/norm.go b/vendor/github.com/montanaflynn/stats/norm.go
index 4eb8eb8..620c5ac 100644
--- a/vendor/github.com/montanaflynn/stats/norm.go
+++ b/vendor/github.com/montanaflynn/stats/norm.go
@@ -7,6 +7,12 @@ import (
"time"
)
+// NormSample generates random samples from a normal distribution
+// with the given mean (loc) and standard deviation (scale).
+func NormSample(loc float64, scale float64, size int) []float64 {
+ return NormBoxMullerRvs(loc, scale, size)
+}
+
// NormPpfRvs generates random variates using the Point Percentile Function.
// For more information please visit: https://demonstrations.wolfram.com/TheMethodOfInverseTransforms/
func NormPpfRvs(loc float64, scale float64, size int) []float64 {
diff --git a/vendor/github.com/montanaflynn/stats/percentile_of_score.go b/vendor/github.com/montanaflynn/stats/percentile_of_score.go
new file mode 100644
index 0000000..a958c95
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/percentile_of_score.go
@@ -0,0 +1,31 @@
+package stats
+
+import "math"
+
+// PercentileOfScore calculates the percentile rank of a score
+// relative to a slice of floats, defined as the percentage of
+// values strictly below the score plus half the percentage of
+// values equal to the score. The result is between 0 and 100.
+// This matches the behavior of Python's
+// scipy.stats.percentileofscore with kind="rank".
+func PercentileOfScore(input Float64Data, score float64) (float64, error) {
+ if input.Len() == 0 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ var below, equal float64
+ for _, v := range input {
+ if v < score {
+ below++
+ } else if v == score {
+ equal++
+ }
+ }
+
+ return 100 * (below + 0.5*equal) / float64(input.Len()), nil
+}
+
+// PercentileOfScore calculates the percentile rank of a score relative to the data
+func (f Float64Data) PercentileOfScore(score float64) (float64, error) {
+ return PercentileOfScore(f, score)
+}
diff --git a/vendor/github.com/montanaflynn/stats/percentile_weighted.go b/vendor/github.com/montanaflynn/stats/percentile_weighted.go
new file mode 100644
index 0000000..beb09a0
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/percentile_weighted.go
@@ -0,0 +1,69 @@
+package stats
+
+import (
+ "math"
+ "sort"
+)
+
+// PercentileWeighted finds the weighted percentile of a slice of floats
+// using the weighted empirical CDF (inverse CDF / nearest-rank method).
+//
+// For a given percent p, it returns the smallest data value x such that
+// the cumulative weight of all values <= x is at least p% of the total
+// weight. This matches the behavior of Python's statsmodels
+// DescrStatsW.quantile.
+//
+// The data and weights slices must be the same length. Weights must be
+// non-negative and at least one weight must be positive. The percent
+// parameter must be between 0 and 100 (exclusive).
+func PercentileWeighted(data, weights Float64Data, percent float64) (percentile float64, err error) {
+ l := data.Len()
+ if l == 0 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ if weights.Len() != l {
+ return math.NaN(), ErrSize
+ }
+
+ if percent <= 0 || percent > 100 {
+ return math.NaN(), ErrBounds
+ }
+
+ // Build sorted pairs by data value
+ type pair struct {
+ value float64
+ weight float64
+ }
+ pairs := make([]pair, l)
+ totalWeight := 0.0
+ for i := 0; i < l; i++ {
+ if weights[i] < 0 {
+ return math.NaN(), ErrNegative
+ }
+ pairs[i] = pair{data[i], weights[i]}
+ totalWeight += weights[i]
+ }
+
+ if totalWeight == 0 {
+ return math.NaN(), ErrBounds
+ }
+
+ sort.Slice(pairs, func(i, j int) bool {
+ return pairs[i].value < pairs[j].value
+ })
+
+ // Find the smallest value where cumulative weight >= target
+ target := (percent / 100) * totalWeight
+ cumWeight := 0.0
+ result := pairs[l-1].value
+ for i := 0; i < l; i++ {
+ cumWeight += pairs[i].weight
+ if cumWeight >= target {
+ result = pairs[i].value
+ break
+ }
+ }
+
+ return result, nil
+}
diff --git a/vendor/github.com/montanaflynn/stats/product.go b/vendor/github.com/montanaflynn/stats/product.go
new file mode 100644
index 0000000..d5ded82
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/product.go
@@ -0,0 +1,26 @@
+package stats
+
+import "math"
+
+// Product calculates the product of a slice of floats by
+// multiplying the values from left to right. It is the scalar
+// counterpart of CumulativeProduct. Large inputs can overflow
+// to Inf; use GeometricMean for an overflow-safe summary of
+// multiplicative data.
+func Product(input Float64Data) (float64, error) {
+ if input.Len() == 0 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ product := 1.0
+ for _, v := range input {
+ product *= v
+ }
+
+ return product, nil
+}
+
+// Product calculates the product of the data
+func (f Float64Data) Product() (float64, error) {
+ return Product(f)
+}
diff --git a/vendor/github.com/montanaflynn/stats/rank.go b/vendor/github.com/montanaflynn/stats/rank.go
new file mode 100644
index 0000000..0e9f861
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/rank.go
@@ -0,0 +1,16 @@
+package stats
+
+// Rank assigns fractional (average) ranks to the input values.
+// Ranks are 1-based and tied values receive the average of the
+// ranks they would have been assigned.
+func Rank(input Float64Data) ([]float64, error) {
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+ return rankData(input), nil
+}
+
+// Rank assigns fractional (average) ranks to the input values
+func (f Float64Data) Rank() ([]float64, error) {
+ return Rank(f)
+}
diff --git a/vendor/github.com/montanaflynn/stats/rescale.go b/vendor/github.com/montanaflynn/stats/rescale.go
new file mode 100644
index 0000000..814fce0
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/rescale.go
@@ -0,0 +1,29 @@
+package stats
+
+// Rescale normalizes the input values to the range of 0 to 1
+// by subtracting the minimum and dividing by the range,
+// also known as min-max normalization.
+func Rescale(input Float64Data) ([]float64, error) {
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ min, _ := Min(input)
+ max, _ := Max(input)
+
+ if max == min {
+ return nil, ErrZero
+ }
+
+ r := make([]float64, len(input))
+ for i, v := range input {
+ r[i] = (v - min) / (max - min)
+ }
+ return r, nil
+}
+
+// Rescale normalizes the input values to the range of 0 to 1
+// by subtracting the minimum and dividing by the range
+func (f Float64Data) Rescale() ([]float64, error) {
+ return Rescale(f)
+}
diff --git a/vendor/github.com/montanaflynn/stats/rms.go b/vendor/github.com/montanaflynn/stats/rms.go
new file mode 100644
index 0000000..7599e3d
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/rms.go
@@ -0,0 +1,23 @@
+package stats
+
+import "math"
+
+// RMS calculates the root mean square of a slice of floats,
+// defined as the square root of the mean of the squared values.
+func RMS(input Float64Data) (float64, error) {
+ if input.Len() == 0 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ var sumSquares float64
+ for _, v := range input {
+ sumSquares += v * v
+ }
+
+ return math.Sqrt(sumSquares / float64(input.Len())), nil
+}
+
+// RMS calculates the root mean square of the data
+func (f Float64Data) RMS() (float64, error) {
+ return RMS(f)
+}
diff --git a/vendor/github.com/montanaflynn/stats/rolling.go b/vendor/github.com/montanaflynn/stats/rolling.go
new file mode 100644
index 0000000..571eb59
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/rolling.go
@@ -0,0 +1,65 @@
+package stats
+
+// MovingAverage calculates the rolling mean of the input over a trailing
+// window. Only fully-populated windows produce output, so the result has
+// len(input)-window+1 entries and entry i is the mean of input[i : i+window].
+// The window must satisfy 1 <= window <= len(input) or ErrBounds is
+// returned. An empty input returns ErrEmptyInput.
+func MovingAverage(input Float64Data, window int) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ if window < 1 || window > input.Len() {
+ return nil, ErrBounds
+ }
+
+ output := make([]float64, input.Len()-window+1)
+
+ for i := range output {
+ // Mean cannot fail here since every window is non-empty
+ mean, _ := Mean(input[i : i+window])
+ output[i] = mean
+ }
+
+ return output, nil
+}
+
+// MovingStdDev calculates the rolling sample standard deviation of the input
+// over a trailing window. Only fully-populated windows produce output, so the
+// result has len(input)-window+1 entries and entry i is the sample standard
+// deviation of input[i : i+window]. The window must satisfy
+// 2 <= window <= len(input) or ErrBounds is returned, since the sample
+// standard deviation of a single value is undefined. An empty input returns
+// ErrEmptyInput.
+func MovingStdDev(input Float64Data, window int) ([]float64, error) {
+
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ if window < 2 || window > input.Len() {
+ return nil, ErrBounds
+ }
+
+ output := make([]float64, input.Len()-window+1)
+
+ for i := range output {
+ // StandardDeviationSample cannot fail here since every window is non-empty
+ sdev, _ := StandardDeviationSample(input[i : i+window])
+ output[i] = sdev
+ }
+
+ return output, nil
+}
+
+// MovingAverage returns the rolling mean of the data over a trailing window
+func (f Float64Data) MovingAverage(window int) ([]float64, error) {
+ return MovingAverage(f, window)
+}
+
+// MovingStdDev returns the rolling sample standard deviation of the data over a trailing window
+func (f Float64Data) MovingStdDev(window int) ([]float64, error) {
+ return MovingStdDev(f, window)
+}
diff --git a/vendor/github.com/montanaflynn/stats/round.go b/vendor/github.com/montanaflynn/stats/round.go
index b66779c..7e122a6 100644
--- a/vendor/github.com/montanaflynn/stats/round.go
+++ b/vendor/github.com/montanaflynn/stats/round.go
@@ -4,35 +4,9 @@ import "math"
// Round a float to a specific decimal place or precision
func Round(input float64, places int) (rounded float64, err error) {
-
- // If the float is not a number
if math.IsNaN(input) {
return math.NaN(), NaNErr
}
-
- // Find out the actual sign and correct the input for later
- sign := 1.0
- if input < 0 {
- sign = -1
- input *= -1
- }
-
- // Use the places arg to get the amount of precision wanted
precision := math.Pow(10, float64(places))
-
- // Find the decimal place we are looking to round
- digit := input * precision
-
- // Get the actual decimal number as a fraction to be compared
- _, decimal := math.Modf(digit)
-
- // If the decimal is less than .5 we round down otherwise up
- if decimal >= 0.5 {
- rounded = math.Ceil(digit)
- } else {
- rounded = math.Floor(digit)
- }
-
- // Finally we do the math to actually create a rounded number
- return rounded / precision * sign, nil
+ return math.Round(input*precision) / precision, nil
}
diff --git a/vendor/github.com/montanaflynn/stats/sem.go b/vendor/github.com/montanaflynn/stats/sem.go
new file mode 100644
index 0000000..111b46e
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/sem.go
@@ -0,0 +1,24 @@
+package stats
+
+import "math"
+
+// SEM calculates the standard error of the mean of a slice
+// of floats, defined as the sample standard deviation divided
+// by the square root of the sample size. This matches the
+// behavior of Python's scipy.stats.sem with ddof=1.
+func SEM(input Float64Data) (float64, error) {
+ if input.Len() == 0 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ // Input is known to be non-empty so the sample standard
+ // deviation cannot return an error
+ sd, _ := StandardDeviationSample(input)
+
+ return sd / math.Sqrt(float64(input.Len())), nil
+}
+
+// SEM calculates the standard error of the mean of the data
+func (f Float64Data) SEM() (float64, error) {
+ return SEM(f)
+}
diff --git a/vendor/github.com/montanaflynn/stats/trimmed_mean.go b/vendor/github.com/montanaflynn/stats/trimmed_mean.go
new file mode 100644
index 0000000..0a99595
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/trimmed_mean.go
@@ -0,0 +1,38 @@
+package stats
+
+import "math"
+
+// TrimmedMean finds the mean of a slice of floats after removing a
+// fraction of the smallest and largest values. This matches the
+// behavior of Python's scipy.stats.trim_mean.
+//
+// The percent parameter is the fraction removed from each tail and
+// must be in the range [0, 0.5). The number of elements trimmed from
+// each tail is floor(len(input) * percent). A percent of zero returns
+// the same result as Mean.
+func TrimmedMean(input Float64Data, percent float64) (float64, error) {
+ l := input.Len()
+ if l == 0 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ // Reject percents outside [0, 0.5) including NaN. Since percent is
+ // strictly below 0.5 at least one element always remains after
+ // trimming floor(l * percent) elements from each tail.
+ if !(percent >= 0 && percent < 0.5) {
+ return math.NaN(), ErrBounds
+ }
+
+ sorted := sortedCopy(input)
+
+ // Number of elements removed from each tail
+ k := int(math.Floor(float64(l) * percent))
+
+ return Mean(sorted[k : l-k])
+}
+
+// TrimmedMean finds the mean of the data after removing a fraction of
+// the smallest and largest values from each tail
+func (f Float64Data) TrimmedMean(percent float64) (float64, error) {
+ return TrimmedMean(f, percent)
+}
diff --git a/vendor/github.com/montanaflynn/stats/ttest.go b/vendor/github.com/montanaflynn/stats/ttest.go
new file mode 100644
index 0000000..f36ea32
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/ttest.go
@@ -0,0 +1,128 @@
+package stats
+
+import "math"
+
+// TTest performs a one-sample or two-sample (independent) Student's t-test.
+//
+// For a one-sample t-test, pass the sample data as data1, nil for data2,
+// and the expected population mean as populationMean.
+//
+// For a two-sample independent t-test (assuming equal variance), pass both
+// sample datasets. The populationMean parameter is ignored in this case.
+//
+// Returns the t statistic and the two-tailed p-value.
+//
+// https://en.wikipedia.org/wiki/Student%27s_t-test
+func TTest(data1, data2 Float64Data, populationMean float64) (t float64, pvalue float64, err error) {
+
+ n1 := data1.Len()
+ if n1 == 0 {
+ return math.NaN(), math.NaN(), ErrEmptyInput
+ }
+
+ mean1, _ := Mean(data1)
+
+ // Two-sample independent t-test (equal variance)
+ if data2 != nil && data2.Len() > 0 {
+ n2 := data2.Len()
+
+ if n1+n2 < 3 {
+ return math.NaN(), math.NaN(), ErrBounds
+ }
+
+ mean2, _ := Mean(data2)
+ var1, _ := SampleVariance(data1)
+ var2, _ := SampleVariance(data2)
+
+ df := float64(n1 + n2 - 2)
+ pooledVar := (float64(n1-1)*var1 + float64(n2-1)*var2) / df
+ se := math.Sqrt(pooledVar * (1.0/float64(n1) + 1.0/float64(n2)))
+ t = (mean1 - mean2) / se
+ pvalue = 2 * tSf(math.Abs(t), df)
+ } else {
+ // One-sample t-test
+ if n1 < 2 {
+ return math.NaN(), math.NaN(), ErrBounds
+ }
+
+ sd, _ := StandardDeviationSample(data1)
+ if sd == 0 {
+ if mean1 == populationMean {
+ return 0, 1.0, nil
+ }
+ return math.NaN(), math.NaN(), ErrBounds
+ }
+ se := sd / math.Sqrt(float64(n1))
+ t = (mean1 - populationMean) / se
+ df := float64(n1 - 1)
+ pvalue = 2 * tSf(math.Abs(t), df)
+ }
+
+ return t, pvalue, nil
+}
+
+// tSf is the survival function for Student's t-distribution.
+// It computes 1 - CDF(t, df) using the regularized incomplete beta function.
+func tSf(t float64, df float64) float64 {
+ x := df / (df + t*t)
+ return 0.5 * regIncBeta(df/2.0, 0.5, x)
+}
+
+// regIncBeta computes the regularized incomplete beta function I_x(a, b)
+// using a continued fraction approximation (Lentz's algorithm).
+func regIncBeta(a, b, x float64) float64 {
+ if x == 0 || x == 1 {
+ return x
+ }
+
+ lbeta := lgammaBeta(a, b)
+ front := math.Exp(math.Log(x)*a + math.Log(1-x)*b - lbeta) / a
+
+ // Use Lentz's continued fraction algorithm
+ f := 1.0
+ c := 1.0
+ d := clampTiny(1.0 - (a+b)*x/(a+1))
+ d = 1.0 / d
+ f = d
+
+ for i := 1; i <= 200; i++ {
+ m := float64(i)
+ // Numerator for even step
+ num := m * (b - m) * x / ((a + 2*m - 1) * (a + 2*m))
+ d = clampTiny(1.0 + num*d)
+ c = clampTiny(1.0 + num/c)
+ d = 1.0 / d
+ f *= c * d
+
+ // Numerator for odd step
+ num = -(a + m) * (a + b + m) * x / ((a + 2*m) * (a + 2*m + 1))
+ d = clampTiny(1.0 + num*d)
+ c = clampTiny(1.0 + num/c)
+ d = 1.0 / d
+ delta := c * d
+ f *= delta
+
+ if math.Abs(delta-1.0) < 1e-10 {
+ break
+ }
+ }
+
+ return front * f
+}
+
+// clampTiny prevents division by zero in Lentz's continued fraction
+// algorithm by replacing near-zero values with a small constant.
+func clampTiny(v float64) float64 {
+ if math.Abs(v) < 1e-30 {
+ return 1e-30
+ }
+ return v
+}
+
+// lgammaBeta computes log(Beta(a, b)) = log(Gamma(a)) + log(Gamma(b)) - log(Gamma(a+b))
+func lgammaBeta(a, b float64) float64 {
+ la, _ := math.Lgamma(a)
+ lb, _ := math.Lgamma(b)
+ lab, _ := math.Lgamma(a + b)
+ return la + lb - lab
+}
diff --git a/vendor/github.com/montanaflynn/stats/weighted_mean.go b/vendor/github.com/montanaflynn/stats/weighted_mean.go
new file mode 100644
index 0000000..b2c20c3
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/weighted_mean.go
@@ -0,0 +1,42 @@
+package stats
+
+import "math"
+
+// WeightedMean finds the weighted mean of a slice of floats, defined as
+// the sum of each data value multiplied by its weight divided by the sum
+// of all the weights. This matches the behavior of Python's
+// numpy.average with the weights argument.
+//
+// The data and weights slices must be the same length. Weights must be
+// non-negative and at least one weight must be positive.
+func WeightedMean(data, weights Float64Data) (float64, error) {
+ l := data.Len()
+ if l == 0 {
+ return math.NaN(), ErrEmptyInput
+ }
+
+ if weights.Len() != l {
+ return math.NaN(), ErrSize
+ }
+
+ weightedSum := 0.0
+ totalWeight := 0.0
+ for i := 0; i < l; i++ {
+ if weights[i] < 0 {
+ return math.NaN(), ErrNegative
+ }
+ weightedSum += data[i] * weights[i]
+ totalWeight += weights[i]
+ }
+
+ if totalWeight == 0 {
+ return math.NaN(), ErrZero
+ }
+
+ return weightedSum / totalWeight, nil
+}
+
+// WeightedMean finds the weighted mean of the data using the given weights
+func (f Float64Data) WeightedMean(weights Float64Data) (float64, error) {
+ return WeightedMean(f, weights)
+}
diff --git a/vendor/github.com/montanaflynn/stats/winsorize.go b/vendor/github.com/montanaflynn/stats/winsorize.go
new file mode 100644
index 0000000..87776be
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/winsorize.go
@@ -0,0 +1,50 @@
+package stats
+
+import "math"
+
+// Winsorize limits the effect of outliers in a slice of floats by
+// clamping a fraction of the smallest and largest values. This matches
+// the behavior of Python's scipy.stats.mstats.winsorize with symmetric
+// limits.
+//
+// The percent parameter is the fraction clamped in each tail and must
+// be in the range [0, 0.5). With k = floor(len(input) * percent),
+// values below the k-th smallest value are set to it and values above
+// the k-th largest value are set to it. The returned slice preserves
+// the original element order and a percent of zero returns a copy of
+// the input.
+func Winsorize(input Float64Data, percent float64) ([]float64, error) {
+ l := input.Len()
+ if l == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ // Reject percents outside [0, 0.5) including NaN
+ if !(percent >= 0 && percent < 0.5) {
+ return nil, ErrBounds
+ }
+
+ sorted := sortedCopy(input)
+
+ // Number of elements clamped in each tail
+ k := int(math.Floor(float64(l) * percent))
+ lower := sorted[k]
+ upper := sorted[l-1-k]
+
+ output := copyslice(input)
+ for i, v := range output {
+ if v < lower {
+ output[i] = lower
+ } else if v > upper {
+ output[i] = upper
+ }
+ }
+
+ return output, nil
+}
+
+// Winsorize returns a copy of the data with a fraction of the smallest
+// and largest values in each tail clamped
+func (f Float64Data) Winsorize(percent float64) ([]float64, error) {
+ return Winsorize(f, percent)
+}
diff --git a/vendor/github.com/montanaflynn/stats/zscore.go b/vendor/github.com/montanaflynn/stats/zscore.go
new file mode 100644
index 0000000..bc256f3
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/zscore.go
@@ -0,0 +1,29 @@
+package stats
+
+// ZScore standardizes the input values by subtracting the mean
+// and dividing by the sample standard deviation, returning the
+// number of standard deviations each value is from the mean.
+func ZScore(input Float64Data) ([]float64, error) {
+ if input.Len() == 0 {
+ return nil, ErrEmptyInput
+ }
+
+ m, _ := Mean(input)
+ sd, _ := StandardDeviationSample(input)
+
+ if sd == 0 {
+ return nil, ErrZero
+ }
+
+ z := make([]float64, len(input))
+ for i, v := range input {
+ z[i] = (v - m) / sd
+ }
+ return z, nil
+}
+
+// ZScore standardizes the input values by subtracting the mean
+// and dividing by the sample standard deviation
+func (f Float64Data) ZScore() ([]float64, error) {
+ return ZScore(f)
+}
diff --git a/vendor/github.com/montanaflynn/stats/ztest.go b/vendor/github.com/montanaflynn/stats/ztest.go
new file mode 100644
index 0000000..eb85553
--- /dev/null
+++ b/vendor/github.com/montanaflynn/stats/ztest.go
@@ -0,0 +1,50 @@
+package stats
+
+import "math"
+
+// ZTest performs a one-sample or two-sample Z-test.
+//
+// For a one-sample Z-test, pass the sample data as data1, nil for data2,
+// the known population mean as populationMean, and the known population
+// standard deviation as populationStdDev.
+//
+// For a two-sample Z-test, pass both sample datasets and the known population
+// standard deviations. The populationMean parameter is ignored in this case.
+//
+// Returns the Z statistic and the two-tailed p-value.
+//
+// https://en.wikipedia.org/wiki/Z-test
+func ZTest(data1, data2 Float64Data, populationMean, populationStdDev float64) (z float64, pvalue float64, err error) {
+
+ n1 := data1.Len()
+ if n1 == 0 {
+ return math.NaN(), math.NaN(), ErrEmptyInput
+ }
+
+ mean1, _ := Mean(data1)
+
+ // Two-sample Z-test
+ if data2 != nil && data2.Len() > 0 {
+ n2 := data2.Len()
+ mean2, _ := Mean(data2)
+
+ if populationStdDev <= 0 {
+ return math.NaN(), math.NaN(), ErrBounds
+ }
+
+ se := populationStdDev * math.Sqrt(1.0/float64(n1)+1.0/float64(n2))
+ z = (mean1 - mean2) / se
+ } else {
+ // One-sample Z-test
+ if populationStdDev <= 0 {
+ return math.NaN(), math.NaN(), ErrBounds
+ }
+
+ se := populationStdDev / math.Sqrt(float64(n1))
+ z = (mean1 - populationMean) / se
+ }
+
+ pvalue = 2 * NormSf(math.Abs(z), 0, 1)
+
+ return z, pvalue, nil
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index f93f686..9e550d2 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -55,7 +55,7 @@ github.com/mdlayher/socket
# github.com/mdlayher/vsock v1.2.1
## explicit; go 1.20
github.com/mdlayher/vsock
-# github.com/montanaflynn/stats v0.9.0
+# github.com/montanaflynn/stats v0.11.0
## explicit; go 1.13
github.com/montanaflynn/stats
# github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822