mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
libnetwork/networkdb: test quality of mRandomNodes
TestNetworkDBAlwaysConverges will occasionally find a failure where one entry is missing on one node even after waiting a full five minutes. One possible explanation is that the selection of nodes to gossip with is biased in some way. Test that the mRandomNodes function picks a uniformly distributed sample of node IDs of sufficient length. The new test reveals that mRandomNodes may sometimes pick out a sample of fewer than m nodes even when the number of nodes to pick from (excluding the local node) is >= m. Put the test behind an xfail tag so it is opt-in to run, without interfering with CI or bisecting. Signed-off-by: Cory Snider <csnider@mirantis.com>
This commit is contained in:
155
daemon/libnetwork/networkdb/cluster_test.go
Normal file
155
daemon/libnetwork/networkdb/cluster_test.go
Normal file
@@ -0,0 +1,155 @@
|
||||
//go:build xfail
|
||||
|
||||
package networkdb
|
||||
|
||||
import (
|
||||
"maps"
|
||||
"math"
|
||||
"math/bits"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/montanaflynn/stats"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
"pgregory.net/rapid"
|
||||
)
|
||||
|
||||
func TestMRandomNodes(t *testing.T) {
|
||||
cfg := DefaultConfig()
|
||||
// The easiest way to ensure that we don't accidentally generate node
|
||||
// IDs that match the local one is to include runes that the generator
|
||||
// will never emit.
|
||||
cfg.NodeID = "_thisnode"
|
||||
uut := newNetworkDB(cfg)
|
||||
|
||||
t.Run("EmptySlice", func(t *testing.T) {
|
||||
sample := uut.mRandomNodes(3, nil)
|
||||
assert.Check(t, is.Len(sample, 0))
|
||||
})
|
||||
|
||||
t.Run("OnlyLocalNode", func(t *testing.T) {
|
||||
sample := uut.mRandomNodes(3, []string{cfg.NodeID})
|
||||
assert.Check(t, is.Len(sample, 0))
|
||||
})
|
||||
|
||||
gen := rapid.Custom(func(t *rapid.T) []string {
|
||||
s := rapid.SliceOfNDistinct(rapid.StringMatching(`[a-z]{10}`), 0, 100, rapid.ID).Draw(t, "node-names")
|
||||
insertPoint := rapid.IntRange(0, len(s)).Draw(t, "insertPoint")
|
||||
return slices.Insert(s, insertPoint, cfg.NodeID)
|
||||
})
|
||||
|
||||
rapid.Check(t, func(t *rapid.T) {
|
||||
nodes := gen.Draw(t, "nodes")
|
||||
m := rapid.IntRange(0, len(nodes)).Draw(t, "m")
|
||||
|
||||
takeSample := func() []string {
|
||||
sample := uut.mRandomNodes(m, nodes)
|
||||
assert.Check(t, is.Len(sample, min(m, len(nodes)-1)))
|
||||
assert.Check(t, is.Equal(slices.Index(sample, cfg.NodeID), -1), "sample contains local node ID\n%v", sample)
|
||||
assertUniqueElements(t, sample)
|
||||
return sample
|
||||
}
|
||||
|
||||
p := kpermutations(uint64(len(nodes)-1), uint64(m))
|
||||
switch {
|
||||
case p <= 1:
|
||||
// Only one permutation is possible, so cannot test randomness.
|
||||
// Assert the other properties by taking a few samples.
|
||||
for range 100 {
|
||||
_ = takeSample()
|
||||
}
|
||||
return
|
||||
case p <= 10:
|
||||
// With a small number of possible k-permutations, we
|
||||
// can feasibly test how many samples it takes to get
|
||||
// all of them.
|
||||
seen := make(map[string]bool)
|
||||
var i int
|
||||
for i = range 10000 {
|
||||
sample := takeSample()
|
||||
seen[strings.Join(sample, ",")] = true
|
||||
if len(seen) == int(p) {
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.Check(t, is.Len(seen, int(p)), "did not see all %d permutations after %d trials", p, i+1)
|
||||
t.Logf("saw all %d permutations after %d samples", p, i+1)
|
||||
default:
|
||||
uniques := 0
|
||||
sample1 := takeSample()
|
||||
for range 10 {
|
||||
sample2 := takeSample()
|
||||
if !slices.Equal(sample1, sample2) {
|
||||
uniques++
|
||||
}
|
||||
}
|
||||
assert.Check(t, uniques > 0, "mRandomNodes returned the same sample multiple times")
|
||||
}
|
||||
|
||||
// We are testing randomness so statistical outliers are
|
||||
// occasionally expected even when the probability
|
||||
// distribution is uniform. Run multiple trials to make
|
||||
// test flakes unlikely in practice.
|
||||
extremes := 0
|
||||
for range 10 {
|
||||
counts := make(map[string]int)
|
||||
for _, n := range nodes {
|
||||
if n != cfg.NodeID {
|
||||
counts[n] = 0
|
||||
}
|
||||
}
|
||||
const samples = 10000
|
||||
for range samples {
|
||||
for _, n := range uut.mRandomNodes(m, nodes) {
|
||||
counts[n]++
|
||||
}
|
||||
}
|
||||
// Adding multiple samples together should yield a normal distribution
|
||||
// if the samples are unbiased.
|
||||
countsf := stats.LoadRawData(slices.Collect(maps.Values(counts)))
|
||||
nf := stats.NormFit(countsf)
|
||||
mean, stdev := nf[0], nf[1]
|
||||
minv, _ := countsf.Min()
|
||||
maxv, _ := countsf.Max()
|
||||
if minv < mean-4*stdev || maxv > mean+4*stdev {
|
||||
extremes++
|
||||
t.Logf("Mean: %f, StdDev: %f, Min: %f, Max: %f", mean, stdev, minv, maxv)
|
||||
}
|
||||
}
|
||||
assert.Check(t, extremes <= 2, "outliers in distribution: %d/10 trials, expected <2/10", extremes)
|
||||
})
|
||||
}
|
||||
|
||||
func assertUniqueElements[S ~[]E, E comparable](t rapid.TB, s S) {
|
||||
t.Helper()
|
||||
counts := make(map[E]int)
|
||||
for _, e := range s {
|
||||
counts[e]++
|
||||
}
|
||||
for e, c := range counts {
|
||||
assert.Equal(t, c, 1, "element %v appears more than once in the slice", e)
|
||||
}
|
||||
}
|
||||
|
||||
// kpermutations returns P(n,k), the number of permutations of k elements chosen
|
||||
// from a set of size n. The calculation is saturating: if the result is larger than
|
||||
// can be represented by a uint64, math.MaxUint64 is returned.
|
||||
func kpermutations(n, k uint64) uint64 {
|
||||
if k > n {
|
||||
return 0
|
||||
}
|
||||
if k == 0 || n == 0 {
|
||||
return 1
|
||||
}
|
||||
p := uint64(1)
|
||||
for i := range k {
|
||||
var hi uint64
|
||||
hi, p = bits.Mul64(p, n-i)
|
||||
if hi != 0 {
|
||||
return math.MaxUint64
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
@@ -80,6 +80,7 @@ require (
|
||||
github.com/moby/sys/user v0.4.0
|
||||
github.com/moby/sys/userns v0.1.0
|
||||
github.com/moby/term v0.5.2
|
||||
github.com/montanaflynn/stats v0.7.1
|
||||
github.com/morikuni/aec v1.0.0
|
||||
github.com/opencontainers/cgroups v0.0.4
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
|
||||
@@ -423,6 +423,8 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJ
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
|
||||
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474/go.mod h1:OQA4XLvDbMgS8P0CevmM4m9Q3Jq4phKUzcocxuGJ5m8=
|
||||
|
||||
7
vendor/github.com/montanaflynn/stats/.gitignore
generated
vendored
Normal file
7
vendor/github.com/montanaflynn/stats/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
coverage.out
|
||||
coverage.txt
|
||||
release-notes.txt
|
||||
.directory
|
||||
.chglog
|
||||
.vscode
|
||||
.DS_Store
|
||||
534
vendor/github.com/montanaflynn/stats/CHANGELOG.md
generated
vendored
Normal file
534
vendor/github.com/montanaflynn/stats/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,534 @@
|
||||
<a name="unreleased"></a>
|
||||
## [Unreleased]
|
||||
|
||||
|
||||
<a name="v0.7.1"></a>
|
||||
## [v0.7.1] - 2023-05-11
|
||||
### Add
|
||||
- Add describe functions ([#77](https://github.com/montanaflynn/stats/issues/77))
|
||||
|
||||
### Update
|
||||
- Update .gitignore
|
||||
- Update README.md, LICENSE and DOCUMENTATION.md files
|
||||
- Update github action go workflow to run on push
|
||||
|
||||
|
||||
<a name="v0.7.0"></a>
|
||||
## [v0.7.0] - 2023-01-08
|
||||
### Add
|
||||
- Add geometric distribution functions ([#75](https://github.com/montanaflynn/stats/issues/75))
|
||||
- Add GitHub action go workflow
|
||||
|
||||
### Remove
|
||||
- Remove travis CI config
|
||||
|
||||
### Update
|
||||
- Update changelog with v0.7.0 changes
|
||||
- Update changelog with v0.7.0 changes
|
||||
- Update github action go workflow
|
||||
- Update geometric distribution tests
|
||||
|
||||
|
||||
<a name="v0.6.6"></a>
|
||||
## [v0.6.6] - 2021-04-26
|
||||
### Add
|
||||
- Add support for string and io.Reader in LoadRawData (pr [#68](https://github.com/montanaflynn/stats/issues/68))
|
||||
- Add latest versions of Go to test against
|
||||
|
||||
### Update
|
||||
- Update changelog with v0.6.6 changes
|
||||
|
||||
### Use
|
||||
- Use math.Sqrt in StandardDeviation (PR [#64](https://github.com/montanaflynn/stats/issues/64))
|
||||
|
||||
|
||||
<a name="v0.6.5"></a>
|
||||
## [v0.6.5] - 2021-02-21
|
||||
### Add
|
||||
- Add Float64Data.Quartiles documentation
|
||||
- Add Quartiles method to Float64Data type (issue [#60](https://github.com/montanaflynn/stats/issues/60))
|
||||
|
||||
### Fix
|
||||
- Fix make release changelog command and add changelog history
|
||||
|
||||
### Update
|
||||
- Update changelog with v0.6.5 changes
|
||||
- Update changelog with v0.6.4 changes
|
||||
- Update README.md links to CHANGELOG.md and DOCUMENTATION.md
|
||||
- Update README.md and Makefile with new release commands
|
||||
|
||||
|
||||
<a name="v0.6.4"></a>
|
||||
## [v0.6.4] - 2021-01-13
|
||||
### Fix
|
||||
- Fix failing tests due to precision errors on arm64 ([#58](https://github.com/montanaflynn/stats/issues/58))
|
||||
|
||||
### Update
|
||||
- Update changelog with v0.6.4 changes
|
||||
- Update examples directory to include a README.md used for synopsis
|
||||
- Update go.mod to include go version where modules are enabled by default
|
||||
- Update changelog with v0.6.3 changes
|
||||
|
||||
|
||||
<a name="v0.6.3"></a>
|
||||
## [v0.6.3] - 2020-02-18
|
||||
### Add
|
||||
- Add creating and committing changelog to Makefile release directive
|
||||
- Add release-notes.txt and .chglog directory to .gitignore
|
||||
|
||||
### Update
|
||||
- Update exported tests to use import for better example documentation
|
||||
- Update documentation using godoc2md
|
||||
- Update changelog with v0.6.2 release
|
||||
|
||||
|
||||
<a name="v0.6.2"></a>
|
||||
## [v0.6.2] - 2020-02-18
|
||||
### Fix
|
||||
- Fix linting errcheck warnings in go benchmarks
|
||||
|
||||
### Update
|
||||
- Update Makefile release directive to use correct release name
|
||||
|
||||
|
||||
<a name="v0.6.1"></a>
|
||||
## [v0.6.1] - 2020-02-18
|
||||
### Add
|
||||
- Add StableSample function signature to readme
|
||||
|
||||
### Fix
|
||||
- Fix linting warnings for normal distribution functions formatting and tests
|
||||
|
||||
### Update
|
||||
- Update documentation links and rename DOC.md to DOCUMENTATION.md
|
||||
- Update README with link to pkg.go.dev reference and release section
|
||||
- Update Makefile with new changelog, docs, and release directives
|
||||
- Update DOC.md links to GitHub source code
|
||||
- Update doc.go comment and add DOC.md package reference file
|
||||
- Update changelog using git-chglog
|
||||
|
||||
|
||||
<a name="v0.6.0"></a>
|
||||
## [v0.6.0] - 2020-02-17
|
||||
### Add
|
||||
- Add Normal Distribution Functions ([#56](https://github.com/montanaflynn/stats/issues/56))
|
||||
- Add previous versions of Go to travis CI config
|
||||
- Add check for distinct values in Mode function ([#51](https://github.com/montanaflynn/stats/issues/51))
|
||||
- Add StableSample function ([#48](https://github.com/montanaflynn/stats/issues/48))
|
||||
- Add doc.go file to show description and usage on godoc.org
|
||||
- Add comments to new error and legacy error variables
|
||||
- Add ExampleRound function to tests
|
||||
- Add go.mod file for module support
|
||||
- Add Sigmoid, SoftMax and Entropy methods and tests
|
||||
- Add Entropy documentation, example and benchmarks
|
||||
- Add Entropy function ([#44](https://github.com/montanaflynn/stats/issues/44))
|
||||
|
||||
### Fix
|
||||
- Fix percentile when only one element ([#47](https://github.com/montanaflynn/stats/issues/47))
|
||||
- Fix AutoCorrelation name in comments and remove unneeded Sprintf
|
||||
|
||||
### Improve
|
||||
- Improve documentation section with command comments
|
||||
|
||||
### Remove
|
||||
- Remove very old versions of Go in travis CI config
|
||||
- Remove boolean comparison to get rid of gometalinter warning
|
||||
|
||||
### Update
|
||||
- Update license dates
|
||||
- Update Distance functions signatures to use Float64Data
|
||||
- Update Sigmoid examples
|
||||
- Update error names with backward compatibility
|
||||
|
||||
### Use
|
||||
- Use relative link to examples/main.go
|
||||
- Use a single var block for exported errors
|
||||
|
||||
|
||||
<a name="v0.5.0"></a>
|
||||
## [v0.5.0] - 2019-01-16
|
||||
### Add
|
||||
- Add Sigmoid and Softmax functions
|
||||
|
||||
### Fix
|
||||
- Fix syntax highlighting and add CumulativeSum func
|
||||
|
||||
|
||||
<a name="v0.4.0"></a>
|
||||
## [v0.4.0] - 2019-01-14
|
||||
### Add
|
||||
- Add goreport badge and documentation section to README.md
|
||||
- Add Examples to test files
|
||||
- Add AutoCorrelation and nist tests
|
||||
- Add String method to statsErr type
|
||||
- Add Y coordinate error for ExponentialRegression
|
||||
- Add syntax highlighting ([#43](https://github.com/montanaflynn/stats/issues/43))
|
||||
- Add CumulativeSum ([#40](https://github.com/montanaflynn/stats/issues/40))
|
||||
- Add more tests and rename distance files
|
||||
- Add coverage and benchmarks to azure pipeline
|
||||
- Add go tests to azure pipeline
|
||||
|
||||
### Change
|
||||
- Change travis tip alias to master
|
||||
- Change codecov to coveralls for code coverage
|
||||
|
||||
### Fix
|
||||
- Fix a few lint warnings
|
||||
- Fix example error
|
||||
|
||||
### Improve
|
||||
- Improve test coverage of distance functions
|
||||
|
||||
### Only
|
||||
- Only run travis on stable and tip versions
|
||||
- Only check code coverage on tip
|
||||
|
||||
### Remove
|
||||
- Remove azure CI pipeline
|
||||
- Remove unnecessary type conversions
|
||||
|
||||
### Return
|
||||
- Return EmptyInputErr instead of EmptyInput
|
||||
|
||||
### Set
|
||||
- Set up CI with Azure Pipelines
|
||||
|
||||
|
||||
<a name="0.3.0"></a>
|
||||
## [0.3.0] - 2017-12-02
|
||||
### Add
|
||||
- Add Chebyshev, Manhattan, Euclidean and Minkowski distance functions ([#35](https://github.com/montanaflynn/stats/issues/35))
|
||||
- Add function for computing chebyshev distance. ([#34](https://github.com/montanaflynn/stats/issues/34))
|
||||
- Add support for time.Duration
|
||||
- Add LoadRawData to docs and examples
|
||||
- Add unit test for edge case that wasn't covered
|
||||
- Add unit tests for edge cases that weren't covered
|
||||
- Add pearson alias delegating to correlation
|
||||
- Add CovariancePopulation to Float64Data
|
||||
- Add pearson product-moment correlation coefficient
|
||||
- Add population covariance
|
||||
- Add random slice benchmarks
|
||||
- Add all applicable functions as methods to Float64Data type
|
||||
- Add MIT license badge
|
||||
- Add link to examples/methods.go
|
||||
- Add Protips for usage and documentation sections
|
||||
- Add tests for rounding up
|
||||
- Add webdoc target and remove linting from test target
|
||||
- Add example usage and consolidate contributing information
|
||||
|
||||
### Added
|
||||
- Added MedianAbsoluteDeviation
|
||||
|
||||
### Annotation
|
||||
- Annotation spelling error
|
||||
|
||||
### Auto
|
||||
- auto commit
|
||||
- auto commit
|
||||
|
||||
### Calculate
|
||||
- Calculate correlation with sdev and covp
|
||||
|
||||
### Clean
|
||||
- Clean up README.md and add info for offline docs
|
||||
|
||||
### Consolidated
|
||||
- Consolidated all error values.
|
||||
|
||||
### Fix
|
||||
- Fix Percentile logic
|
||||
- Fix InterQuartileRange method test
|
||||
- Fix zero percent bug and add test
|
||||
- Fix usage example output typos
|
||||
|
||||
### Improve
|
||||
- Improve bounds checking in Percentile
|
||||
- Improve error log messaging
|
||||
|
||||
### Imput
|
||||
- Imput -> Input
|
||||
|
||||
### Include
|
||||
- Include alternative way to set Float64Data in example
|
||||
|
||||
### Make
|
||||
- Make various changes to README.md
|
||||
|
||||
### Merge
|
||||
- Merge branch 'master' of github.com:montanaflynn/stats
|
||||
- Merge master
|
||||
|
||||
### Mode
|
||||
- Mode calculation fix and tests
|
||||
|
||||
### Realized
|
||||
- Realized the obvious efficiency gains of ignoring the unique numbers at the beginning of the slice. Benchmark joy ensued.
|
||||
|
||||
### Refactor
|
||||
- Refactor testing of Round()
|
||||
- Refactor setting Coordinate y field using Exp in place of Pow
|
||||
- Refactor Makefile and add docs target
|
||||
|
||||
### Remove
|
||||
- Remove deep links to types and functions
|
||||
|
||||
### Rename
|
||||
- Rename file from types to data
|
||||
|
||||
### Retrieve
|
||||
- Retrieve InterQuartileRange for the Float64Data.
|
||||
|
||||
### Split
|
||||
- Split up stats.go into separate files
|
||||
|
||||
### Support
|
||||
- Support more types on LoadRawData() ([#36](https://github.com/montanaflynn/stats/issues/36))
|
||||
|
||||
### Switch
|
||||
- Switch default and check targets
|
||||
|
||||
### Update
|
||||
- Update Readme
|
||||
- Update example methods and some text
|
||||
- Update README and include Float64Data type method examples
|
||||
|
||||
### Pull Requests
|
||||
- Merge pull request [#32](https://github.com/montanaflynn/stats/issues/32) from a-robinson/percentile
|
||||
- Merge pull request [#30](https://github.com/montanaflynn/stats/issues/30) from montanaflynn/fix-test
|
||||
- Merge pull request [#29](https://github.com/montanaflynn/stats/issues/29) from edupsousa/master
|
||||
- Merge pull request [#27](https://github.com/montanaflynn/stats/issues/27) from andrey-yantsen/fix-percentile-out-of-bounds
|
||||
- Merge pull request [#25](https://github.com/montanaflynn/stats/issues/25) from kazhuravlev/patch-1
|
||||
- Merge pull request [#22](https://github.com/montanaflynn/stats/issues/22) from JanBerktold/time-duration
|
||||
- Merge pull request [#24](https://github.com/montanaflynn/stats/issues/24) from alouche/master
|
||||
- Merge pull request [#21](https://github.com/montanaflynn/stats/issues/21) from brydavis/master
|
||||
- Merge pull request [#19](https://github.com/montanaflynn/stats/issues/19) from ginodeis/mode-bug
|
||||
- Merge pull request [#17](https://github.com/montanaflynn/stats/issues/17) from Kunde21/master
|
||||
- Merge pull request [#3](https://github.com/montanaflynn/stats/issues/3) from montanaflynn/master
|
||||
- Merge pull request [#2](https://github.com/montanaflynn/stats/issues/2) from montanaflynn/master
|
||||
- Merge pull request [#13](https://github.com/montanaflynn/stats/issues/13) from toashd/pearson
|
||||
- Merge pull request [#12](https://github.com/montanaflynn/stats/issues/12) from alixaxel/MAD
|
||||
- Merge pull request [#1](https://github.com/montanaflynn/stats/issues/1) from montanaflynn/master
|
||||
- Merge pull request [#11](https://github.com/montanaflynn/stats/issues/11) from Kunde21/modeMemReduce
|
||||
- Merge pull request [#10](https://github.com/montanaflynn/stats/issues/10) from Kunde21/ModeRewrite
|
||||
|
||||
|
||||
<a name="0.2.0"></a>
|
||||
## [0.2.0] - 2015-10-14
|
||||
### Add
|
||||
- Add Makefile with gometalinter, testing, benchmarking and coverage report targets
|
||||
- Add comments describing functions and structs
|
||||
- Add Correlation func
|
||||
- Add Covariance func
|
||||
- Add tests for new function shortcuts
|
||||
- Add StandardDeviation function as a shortcut to StandardDeviationPopulation
|
||||
- Add Float64Data and Series types
|
||||
|
||||
### Change
|
||||
- Change Sample to return a standard []float64 type
|
||||
|
||||
### Fix
|
||||
- Fix broken link to Makefile
|
||||
- Fix broken link and simplify code coverage reporting command
|
||||
- Fix go vet warning about printf type placeholder
|
||||
- Fix failing codecov test coverage reporting
|
||||
- Fix link to CHANGELOG.md
|
||||
|
||||
### Fixed
|
||||
- Fixed typographical error, changed accomdate to accommodate in README.
|
||||
|
||||
### Include
|
||||
- Include Variance and StandardDeviation shortcuts
|
||||
|
||||
### Pass
|
||||
- Pass gometalinter
|
||||
|
||||
### Refactor
|
||||
- Refactor Variance function to be the same as population variance
|
||||
|
||||
### Release
|
||||
- Release version 0.2.0
|
||||
|
||||
### Remove
|
||||
- Remove unneeded do packages and update cover URL
|
||||
- Remove sudo from pip install
|
||||
|
||||
### Reorder
|
||||
- Reorder functions and sections
|
||||
|
||||
### Revert
|
||||
- Revert to legacy containers to preserve go1.1 testing
|
||||
|
||||
### Switch
|
||||
- Switch from legacy to container-based CI infrastructure
|
||||
|
||||
### Update
|
||||
- Update contributing instructions and mention Makefile
|
||||
|
||||
### Pull Requests
|
||||
- Merge pull request [#5](https://github.com/montanaflynn/stats/issues/5) from orthographic-pedant/spell_check/accommodate
|
||||
|
||||
|
||||
<a name="0.1.0"></a>
|
||||
## [0.1.0] - 2015-08-19
|
||||
### Add
|
||||
- Add CONTRIBUTING.md
|
||||
|
||||
### Rename
|
||||
- Rename functions while preserving backwards compatibility
|
||||
|
||||
|
||||
<a name="0.0.9"></a>
|
||||
## 0.0.9 - 2015-08-18
|
||||
### Add
|
||||
- Add HarmonicMean func
|
||||
- Add GeometricMean func
|
||||
- Add .gitignore to avoid commiting test coverage report
|
||||
- Add Outliers stuct and QuantileOutliers func
|
||||
- Add Interquartile Range, Midhinge and Trimean examples
|
||||
- Add Trimean
|
||||
- Add Midhinge
|
||||
- Add Inter Quartile Range
|
||||
- Add a unit test to check for an empty slice error
|
||||
- Add Quantiles struct and Quantile func
|
||||
- Add more tests and fix a typo
|
||||
- Add Golang 1.5 to build tests
|
||||
- Add a standard MIT license file
|
||||
- Add basic benchmarking
|
||||
- Add regression models
|
||||
- Add codecov token
|
||||
- Add codecov
|
||||
- Add check for slices with a single item
|
||||
- Add coverage tests
|
||||
- Add back previous Go versions to Travis CI
|
||||
- Add Travis CI
|
||||
- Add GoDoc badge
|
||||
- Add Percentile and Float64ToInt functions
|
||||
- Add another rounding test for whole numbers
|
||||
- Add build status badge
|
||||
- Add code coverage badge
|
||||
- Add test for NaN, achieving 100% code coverage
|
||||
- Add round function
|
||||
- Add standard deviation function
|
||||
- Add sum function
|
||||
|
||||
### Add
|
||||
- add tests for sample
|
||||
- add sample
|
||||
|
||||
### Added
|
||||
- Added sample and population variance and deviation functions
|
||||
- Added README
|
||||
|
||||
### Adjust
|
||||
- Adjust API ordering
|
||||
|
||||
### Avoid
|
||||
- Avoid unintended consequence of using sort
|
||||
|
||||
### Better
|
||||
- Better performing min/max
|
||||
- Better description
|
||||
|
||||
### Change
|
||||
- Change package path to potentially fix a bug in earlier versions of Go
|
||||
|
||||
### Clean
|
||||
- Clean up README and add some more information
|
||||
- Clean up test error
|
||||
|
||||
### Consistent
|
||||
- Consistent empty slice error messages
|
||||
- Consistent var naming
|
||||
- Consistent func declaration
|
||||
|
||||
### Convert
|
||||
- Convert ints to floats
|
||||
|
||||
### Duplicate
|
||||
- Duplicate packages for all versions
|
||||
|
||||
### Export
|
||||
- Export Coordinate struct fields
|
||||
|
||||
### First
|
||||
- First commit
|
||||
|
||||
### Fix
|
||||
- Fix copy pasta mistake testing the wrong function
|
||||
- Fix error message
|
||||
- Fix usage output and edit API doc section
|
||||
- Fix testing edgecase where map was in wrong order
|
||||
- Fix usage example
|
||||
- Fix usage examples
|
||||
|
||||
### Include
|
||||
- Include the Nearest Rank method of calculating percentiles
|
||||
|
||||
### More
|
||||
- More commenting
|
||||
|
||||
### Move
|
||||
- Move GoDoc link to top
|
||||
|
||||
### Redirect
|
||||
- Redirect kills newer versions of Go
|
||||
|
||||
### Refactor
|
||||
- Refactor code and error checking
|
||||
|
||||
### Remove
|
||||
- Remove unnecassary typecasting in sum func
|
||||
- Remove cover since it doesn't work for later versions of go
|
||||
- Remove golint and gocoveralls
|
||||
|
||||
### Rename
|
||||
- Rename StandardDev to StdDev
|
||||
- Rename StandardDev to StdDev
|
||||
|
||||
### Return
|
||||
- Return errors for all functions
|
||||
|
||||
### Run
|
||||
- Run go fmt to clean up formatting
|
||||
|
||||
### Simplify
|
||||
- Simplify min/max function
|
||||
|
||||
### Start
|
||||
- Start with minimal tests
|
||||
|
||||
### Switch
|
||||
- Switch wercker to travis and update todos
|
||||
|
||||
### Table
|
||||
- table testing style
|
||||
|
||||
### Update
|
||||
- Update README and move the example main.go into it's own file
|
||||
- Update TODO list
|
||||
- Update README
|
||||
- Update usage examples and todos
|
||||
|
||||
### Use
|
||||
- Use codecov the recommended way
|
||||
- Use correct string formatting types
|
||||
|
||||
### Pull Requests
|
||||
- Merge pull request [#4](https://github.com/montanaflynn/stats/issues/4) from saromanov/sample
|
||||
|
||||
|
||||
[Unreleased]: https://github.com/montanaflynn/stats/compare/v0.7.1...HEAD
|
||||
[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
|
||||
[v0.6.6]: https://github.com/montanaflynn/stats/compare/v0.6.5...v0.6.6
|
||||
[v0.6.5]: https://github.com/montanaflynn/stats/compare/v0.6.4...v0.6.5
|
||||
[v0.6.4]: https://github.com/montanaflynn/stats/compare/v0.6.3...v0.6.4
|
||||
[v0.6.3]: https://github.com/montanaflynn/stats/compare/v0.6.2...v0.6.3
|
||||
[v0.6.2]: https://github.com/montanaflynn/stats/compare/v0.6.1...v0.6.2
|
||||
[v0.6.1]: https://github.com/montanaflynn/stats/compare/v0.6.0...v0.6.1
|
||||
[v0.6.0]: https://github.com/montanaflynn/stats/compare/v0.5.0...v0.6.0
|
||||
[v0.5.0]: https://github.com/montanaflynn/stats/compare/v0.4.0...v0.5.0
|
||||
[v0.4.0]: https://github.com/montanaflynn/stats/compare/0.3.0...v0.4.0
|
||||
[0.3.0]: https://github.com/montanaflynn/stats/compare/0.2.0...0.3.0
|
||||
[0.2.0]: https://github.com/montanaflynn/stats/compare/0.1.0...0.2.0
|
||||
[0.1.0]: https://github.com/montanaflynn/stats/compare/0.0.9...0.1.0
|
||||
1271
vendor/github.com/montanaflynn/stats/DOCUMENTATION.md
generated
vendored
Normal file
1271
vendor/github.com/montanaflynn/stats/DOCUMENTATION.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
21
vendor/github.com/montanaflynn/stats/LICENSE
generated
vendored
Normal file
21
vendor/github.com/montanaflynn/stats/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2023 Montana Flynn (https://montanaflynn.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
34
vendor/github.com/montanaflynn/stats/Makefile
generated
vendored
Normal file
34
vendor/github.com/montanaflynn/stats/Makefile
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
.PHONY: all
|
||||
|
||||
default: test lint
|
||||
|
||||
format:
|
||||
go fmt .
|
||||
|
||||
test:
|
||||
go test -race
|
||||
|
||||
check: format test
|
||||
|
||||
benchmark:
|
||||
go test -bench=. -benchmem
|
||||
|
||||
coverage:
|
||||
go test -coverprofile=coverage.out
|
||||
go tool cover -html="coverage.out"
|
||||
|
||||
lint: format
|
||||
golangci-lint run .
|
||||
|
||||
docs:
|
||||
godoc2md github.com/montanaflynn/stats | sed -e s#src/target/##g > DOCUMENTATION.md
|
||||
|
||||
release:
|
||||
git-chglog --output CHANGELOG.md --next-tag ${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 push origin master ${TAG}
|
||||
hub release create --copy -F release-notes.txt ${TAG}
|
||||
|
||||
237
vendor/github.com/montanaflynn/stats/README.md
generated
vendored
Normal file
237
vendor/github.com/montanaflynn/stats/README.md
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
# 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]
|
||||
|
||||
A well tested and comprehensive Golang statistics library / package / module with no dependencies.
|
||||
|
||||
If you have any suggestions, problems or bug reports please [create an issue](https://github.com/montanaflynn/stats/issues) and I'll do my best to accommodate you. In addition simply starring the repo would show your support for the project and be very much appreciated!
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
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:
|
||||
|
||||
```go
|
||||
// start with some source data to use
|
||||
data := []float64{1.0, 2.1, 3.2, 4.823, 4.1, 5.8}
|
||||
|
||||
// you could also use different types like this
|
||||
// data := stats.LoadRawData([]int{1, 2, 3, 4, 5})
|
||||
// data := stats.LoadRawData([]interface{}{1.1, "2", 3})
|
||||
// etc...
|
||||
|
||||
median, _ := stats.Median(data)
|
||||
fmt.Println(median) // 3.65
|
||||
|
||||
roundedMedian, _ := stats.Round(median, 0)
|
||||
fmt.Println(roundedMedian) // 4
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
The entire API documentation is available on [GoDoc.org](http://godoc.org/github.com/montanaflynn/stats) or [pkg.go.dev](https://pkg.go.dev/github.com/montanaflynn/stats).
|
||||
|
||||
You can also view docs offline with the following commands:
|
||||
|
||||
```
|
||||
# Command line
|
||||
godoc . # show all exported apis
|
||||
godoc . Median # show a single function
|
||||
godoc -ex . Round # show function with example
|
||||
godoc . Float64Data # show the type and methods
|
||||
|
||||
# Local website
|
||||
godoc -http=:4444 # start the godoc server on port 4444
|
||||
open http://localhost:4444/pkg/github.com/montanaflynn/stats/
|
||||
```
|
||||
|
||||
The exported API is as follows:
|
||||
|
||||
```go
|
||||
var (
|
||||
ErrEmptyInput = statsError{"Input must not be empty."}
|
||||
ErrNaN = statsError{"Not a number."}
|
||||
ErrNegative = statsError{"Must not contain negative values."}
|
||||
ErrZero = statsError{"Must not contain zero values."}
|
||||
ErrBounds = statsError{"Input is outside of range."}
|
||||
ErrSize = statsError{"Must be the same length."}
|
||||
ErrInfValue = statsError{"Value is infinite."}
|
||||
ErrYCoord = statsError{"Y Value must be greater than zero."}
|
||||
)
|
||||
|
||||
func Round(input float64, places int) (rounded float64, err error) {}
|
||||
|
||||
type Float64Data []float64
|
||||
|
||||
func LoadRawData(raw interface{}) (f Float64Data) {}
|
||||
|
||||
func AutoCorrelation(data Float64Data, lags int) (float64, error) {}
|
||||
func ChebyshevDistance(dataPointX, dataPointY Float64Data) (distance float64, err error) {}
|
||||
func Correlation(data1, data2 Float64Data) (float64, error) {}
|
||||
func Covariance(data1, data2 Float64Data) (float64, error) {}
|
||||
func CovariancePopulation(data1, data2 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 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 InterQuartileRange(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) {}
|
||||
func Median(input Float64Data) (median float64, err error) {}
|
||||
func MedianAbsoluteDeviation(input Float64Data) (mad float64, err error) {}
|
||||
func MedianAbsoluteDeviationPopulation(input Float64Data) (mad float64, err error) {}
|
||||
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 NormBoxMullerRvs(loc float64, scale float64, size int) []float64 {}
|
||||
func NormCdf(x float64, loc float64, scale float64) float64 {}
|
||||
func NormEntropy(loc float64, scale float64) float64 {}
|
||||
func NormFit(data []float64) [2]float64{}
|
||||
func NormInterval(alpha float64, loc float64, scale float64 ) [2]float64 {}
|
||||
func NormIsf(p float64, loc float64, scale float64) (x float64) {}
|
||||
func NormLogCdf(x float64, loc float64, scale float64) float64 {}
|
||||
func NormLogPdf(x float64, loc float64, scale float64) float64 {}
|
||||
func NormLogSf(x float64, loc float64, scale float64) float64 {}
|
||||
func NormMean(loc float64, scale float64) float64 {}
|
||||
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 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 Percentile(input Float64Data, percent float64) (percentile float64, err error) {}
|
||||
func PercentileNearestRank(input Float64Data, percent float64) (percentile float64, err error) {}
|
||||
func PopulationVariance(input Float64Data) (pvar float64, err error) {}
|
||||
func Sample(input Float64Data, takenum int, replacement bool) ([]float64, error) {}
|
||||
func SampleVariance(input Float64Data) (svar float64, err error) {}
|
||||
func Sigmoid(input Float64Data) ([]float64, error) {}
|
||||
func SoftMax(input Float64Data) ([]float64, error) {}
|
||||
func StableSample(input Float64Data, takenum int) ([]float64, error) {}
|
||||
func StandardDeviation(input Float64Data) (sdev float64, err error) {}
|
||||
func StandardDeviationPopulation(input Float64Data) (sdev float64, err error) {}
|
||||
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 Trimean(input Float64Data) (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 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) {}
|
||||
|
||||
type Coordinate struct {
|
||||
X, Y float64
|
||||
}
|
||||
|
||||
type Series []Coordinate
|
||||
|
||||
func ExponentialRegression(s Series) (regressions Series, err error) {}
|
||||
func LinearRegression(s Series) (regressions Series, err error) {}
|
||||
func LogarithmicRegression(s Series) (regressions Series, err error) {}
|
||||
|
||||
type Outliers struct {
|
||||
Mild Float64Data
|
||||
Extreme Float64Data
|
||||
}
|
||||
|
||||
type Quartiles struct {
|
||||
Q1 float64
|
||||
Q2 float64
|
||||
Q3 float64
|
||||
}
|
||||
|
||||
func Quartile(input Float64Data) (Quartiles, error) {}
|
||||
func QuartileOutliers(input Float64Data) (Outliers, error) {}
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull request are always welcome no matter how big or small. I've included a [Makefile](https://github.com/montanaflynn/stats/blob/master/Makefile) that has a lot of helper targets for common actions such as linting, testing, code coverage reporting and more.
|
||||
|
||||
1. Fork the repo and clone your fork
|
||||
2. Create new branch (`git checkout -b some-thing`)
|
||||
3. Make the desired changes
|
||||
4. Ensure tests pass (`go test -cover` or `make test`)
|
||||
5. Run lint and fix problems (`go vet .` or `make lint`)
|
||||
6. Commit changes (`git commit -am 'Did something'`)
|
||||
7. Push branch (`git push origin some-thing`)
|
||||
8. Submit pull request
|
||||
|
||||
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 `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`
|
||||
|
||||
## Releasing
|
||||
|
||||
This is not required by contributors and mostly here as a reminder to myself as the maintainer of this repo. To release a new version we should update the [CHANGELOG.md](/CHANGELOG.md) and [DOCUMENTATION.md](/DOCUMENTATION.md).
|
||||
|
||||
First install the tools used to generate the markdown files and release:
|
||||
|
||||
```
|
||||
go install github.com/davecheney/godoc2md@latest
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
brew tap git-chglog/git-chglog
|
||||
brew install gnu-sed hub git-chglog
|
||||
```
|
||||
|
||||
Then you can run these `make` directives:
|
||||
|
||||
```
|
||||
# Generate DOCUMENTATION.md
|
||||
make docs
|
||||
```
|
||||
|
||||
Then we can create a [CHANGELOG.md](/CHANGELOG.md) a new git tag and a github release:
|
||||
|
||||
```
|
||||
make release TAG=v0.x.x
|
||||
```
|
||||
|
||||
To authenticate `hub` for the release you will need to create a personal access token and use it as the password when it's requested.
|
||||
|
||||
## MIT License
|
||||
|
||||
Copyright (c) 2014-2023 Montana Flynn (https://montanaflynn.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORpublicS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
[action-url]: https://github.com/montanaflynn/stats/actions
|
||||
[action-svg]: https://img.shields.io/github/actions/workflow/status/montanaflynn/stats/go.yml
|
||||
|
||||
[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
|
||||
|
||||
[pkggodev-url]: https://pkg.go.dev/github.com/montanaflynn/stats
|
||||
[pkggodev-svg]: https://gistcdn.githack.com/montanaflynn/b02f1d78d8c0de8435895d7e7cd0d473/raw/17f2a5a69f1323ecd42c00e0683655da96d9ecc8/badge.svg
|
||||
|
||||
[license-url]: https://github.com/montanaflynn/stats/blob/master/LICENSE
|
||||
[license-svg]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||
60
vendor/github.com/montanaflynn/stats/correlation.go
generated
vendored
Normal file
60
vendor/github.com/montanaflynn/stats/correlation.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Correlation describes the degree of relationship between two sets of data
|
||||
func Correlation(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
|
||||
}
|
||||
|
||||
sdev1, _ := StandardDeviationPopulation(data1)
|
||||
sdev2, _ := StandardDeviationPopulation(data2)
|
||||
|
||||
if sdev1 == 0 || sdev2 == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
covp, _ := CovariancePopulation(data1, data2)
|
||||
return covp / (sdev1 * sdev2), nil
|
||||
}
|
||||
|
||||
// Pearson calculates the Pearson product-moment correlation coefficient between two variables
|
||||
func Pearson(data1, data2 Float64Data) (float64, error) {
|
||||
return Correlation(data1, data2)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
mean, _ := Mean(data)
|
||||
|
||||
var result, q float64
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
result = q / v
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
21
vendor/github.com/montanaflynn/stats/cumulative_sum.go
generated
vendored
Normal file
21
vendor/github.com/montanaflynn/stats/cumulative_sum.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package stats
|
||||
|
||||
// CumulativeSum calculates the cumulative sum of the input slice
|
||||
func CumulativeSum(input Float64Data) ([]float64, error) {
|
||||
|
||||
if input.Len() == 0 {
|
||||
return Float64Data{}, EmptyInput
|
||||
}
|
||||
|
||||
cumSum := make([]float64, input.Len())
|
||||
|
||||
for i, val := range input {
|
||||
if i == 0 {
|
||||
cumSum[i] = val
|
||||
} else {
|
||||
cumSum[i] = cumSum[i-1] + val
|
||||
}
|
||||
}
|
||||
|
||||
return cumSum, nil
|
||||
}
|
||||
169
vendor/github.com/montanaflynn/stats/data.go
generated
vendored
Normal file
169
vendor/github.com/montanaflynn/stats/data.go
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
package stats
|
||||
|
||||
// Float64Data is a named type for []float64 with helper methods
|
||||
type Float64Data []float64
|
||||
|
||||
// Get item in slice
|
||||
func (f Float64Data) Get(i int) float64 { return f[i] }
|
||||
|
||||
// Len returns length of slice
|
||||
func (f Float64Data) Len() int { return len(f) }
|
||||
|
||||
// Less returns if one number is less than another
|
||||
func (f Float64Data) Less(i, j int) bool { return f[i] < f[j] }
|
||||
|
||||
// Swap switches out two numbers in slice
|
||||
func (f Float64Data) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
|
||||
|
||||
// Min returns the minimum number in the data
|
||||
func (f Float64Data) Min() (float64, error) { return Min(f) }
|
||||
|
||||
// Max returns the maximum number in the data
|
||||
func (f Float64Data) Max() (float64, error) { return Max(f) }
|
||||
|
||||
// Sum returns the total of all the numbers in the data
|
||||
func (f Float64Data) Sum() (float64, error) { return Sum(f) }
|
||||
|
||||
// CumulativeSum returns the cumulative sum of the data
|
||||
func (f Float64Data) CumulativeSum() ([]float64, error) { return CumulativeSum(f) }
|
||||
|
||||
// Mean returns the mean of the data
|
||||
func (f Float64Data) Mean() (float64, error) { return Mean(f) }
|
||||
|
||||
// Median returns the median of the data
|
||||
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
|
||||
func (f Float64Data) GeometricMean() (float64, error) { return GeometricMean(f) }
|
||||
|
||||
// HarmonicMean returns the mode of the data
|
||||
func (f Float64Data) HarmonicMean() (float64, error) { return HarmonicMean(f) }
|
||||
|
||||
// MedianAbsoluteDeviation the median of the absolute deviations from the dataset median
|
||||
func (f Float64Data) MedianAbsoluteDeviation() (float64, error) {
|
||||
return MedianAbsoluteDeviation(f)
|
||||
}
|
||||
|
||||
// MedianAbsoluteDeviationPopulation finds the median of the absolute deviations from the population median
|
||||
func (f Float64Data) MedianAbsoluteDeviationPopulation() (float64, error) {
|
||||
return MedianAbsoluteDeviationPopulation(f)
|
||||
}
|
||||
|
||||
// StandardDeviation the amount of variation in the dataset
|
||||
func (f Float64Data) StandardDeviation() (float64, error) {
|
||||
return StandardDeviation(f)
|
||||
}
|
||||
|
||||
// StandardDeviationPopulation finds the amount of variation from the population
|
||||
func (f Float64Data) StandardDeviationPopulation() (float64, error) {
|
||||
return StandardDeviationPopulation(f)
|
||||
}
|
||||
|
||||
// StandardDeviationSample finds the amount of variation from a sample
|
||||
func (f Float64Data) StandardDeviationSample() (float64, error) {
|
||||
return StandardDeviationSample(f)
|
||||
}
|
||||
|
||||
// QuartileOutliers finds the mild and extreme outliers
|
||||
func (f Float64Data) QuartileOutliers() (Outliers, error) {
|
||||
return QuartileOutliers(f)
|
||||
}
|
||||
|
||||
// Percentile finds the relative standing in a slice of floats
|
||||
func (f Float64Data) Percentile(p float64) (float64, error) {
|
||||
return Percentile(f, p)
|
||||
}
|
||||
|
||||
// PercentileNearestRank finds the relative standing using the Nearest Rank method
|
||||
func (f Float64Data) PercentileNearestRank(p float64) (float64, error) {
|
||||
return PercentileNearestRank(f, p)
|
||||
}
|
||||
|
||||
// Correlation describes the degree of relationship between two sets of data
|
||||
func (f Float64Data) Correlation(d Float64Data) (float64, error) {
|
||||
return Correlation(f, d)
|
||||
}
|
||||
|
||||
// AutoCorrelation is the correlation of a signal with a delayed copy of itself as a function of delay
|
||||
func (f Float64Data) AutoCorrelation(lags int) (float64, error) {
|
||||
return AutoCorrelation(f, lags)
|
||||
}
|
||||
|
||||
// Pearson calculates the Pearson product-moment correlation coefficient between two variables.
|
||||
func (f Float64Data) Pearson(d Float64Data) (float64, error) {
|
||||
return Pearson(f, d)
|
||||
}
|
||||
|
||||
// Quartile returns the three quartile points from a slice of data
|
||||
func (f Float64Data) Quartile(d Float64Data) (Quartiles, error) {
|
||||
return Quartile(d)
|
||||
}
|
||||
|
||||
// InterQuartileRange finds the range between Q1 and Q3
|
||||
func (f Float64Data) InterQuartileRange() (float64, error) {
|
||||
return InterQuartileRange(f)
|
||||
}
|
||||
|
||||
// Midhinge finds the average of the first and third quartiles
|
||||
func (f Float64Data) Midhinge(d Float64Data) (float64, error) {
|
||||
return Midhinge(d)
|
||||
}
|
||||
|
||||
// Trimean finds the average of the median and the midhinge
|
||||
func (f Float64Data) Trimean(d Float64Data) (float64, error) {
|
||||
return Trimean(d)
|
||||
}
|
||||
|
||||
// Sample returns sample from input with replacement or without
|
||||
func (f Float64Data) Sample(n int, r bool) ([]float64, error) {
|
||||
return Sample(f, n, r)
|
||||
}
|
||||
|
||||
// Variance the amount of variation in the dataset
|
||||
func (f Float64Data) Variance() (float64, error) {
|
||||
return Variance(f)
|
||||
}
|
||||
|
||||
// PopulationVariance finds the amount of variance within a population
|
||||
func (f Float64Data) PopulationVariance() (float64, error) {
|
||||
return PopulationVariance(f)
|
||||
}
|
||||
|
||||
// SampleVariance finds the amount of variance within a sample
|
||||
func (f Float64Data) SampleVariance() (float64, error) {
|
||||
return SampleVariance(f)
|
||||
}
|
||||
|
||||
// Covariance is a measure of how much two sets of data change
|
||||
func (f Float64Data) Covariance(d Float64Data) (float64, error) {
|
||||
return Covariance(f, d)
|
||||
}
|
||||
|
||||
// CovariancePopulation computes covariance for entire population between two variables
|
||||
func (f Float64Data) CovariancePopulation(d Float64Data) (float64, error) {
|
||||
return CovariancePopulation(f, d)
|
||||
}
|
||||
|
||||
// Sigmoid returns the input values along the sigmoid or s-shaped curve
|
||||
func (f Float64Data) Sigmoid() ([]float64, error) {
|
||||
return Sigmoid(f)
|
||||
}
|
||||
|
||||
// SoftMax returns the input values in the range of 0 to 1
|
||||
// with sum of all the probabilities being equal to one.
|
||||
func (f Float64Data) SoftMax() ([]float64, error) {
|
||||
return SoftMax(f)
|
||||
}
|
||||
|
||||
// Entropy provides calculation of the entropy
|
||||
func (f Float64Data) Entropy() (float64, error) {
|
||||
return Entropy(f)
|
||||
}
|
||||
|
||||
// Quartiles returns the three quartile points from instance of Float64Data
|
||||
func (f Float64Data) Quartiles() (Quartiles, error) {
|
||||
return Quartile(f)
|
||||
}
|
||||
81
vendor/github.com/montanaflynn/stats/describe.go
generated
vendored
Normal file
81
vendor/github.com/montanaflynn/stats/describe.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
package stats
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Holds information about the dataset provided to Describe
|
||||
type Description struct {
|
||||
Count int
|
||||
Mean float64
|
||||
Std float64
|
||||
Max float64
|
||||
Min float64
|
||||
DescriptionPercentiles []descriptionPercentile
|
||||
AllowedNaN bool
|
||||
}
|
||||
|
||||
// Specifies percentiles to be computed
|
||||
type descriptionPercentile struct {
|
||||
Percentile float64
|
||||
Value float64
|
||||
}
|
||||
|
||||
// Describe generates descriptive statistics about a provided dataset, similar to python's pandas.describe()
|
||||
func Describe(input Float64Data, allowNaN bool, percentiles *[]float64) (*Description, error) {
|
||||
return DescribePercentileFunc(input, allowNaN, percentiles, Percentile)
|
||||
}
|
||||
|
||||
// Describe generates descriptive statistics about a provided dataset, similar to python's pandas.describe()
|
||||
// Takes in a function to use for percentile calculation
|
||||
func DescribePercentileFunc(input Float64Data, allowNaN bool, percentiles *[]float64, percentileFunc func(Float64Data, float64) (float64, error)) (*Description, error) {
|
||||
var description Description
|
||||
description.AllowedNaN = allowNaN
|
||||
description.Count = input.Len()
|
||||
|
||||
if description.Count == 0 && !allowNaN {
|
||||
return &description, ErrEmptyInput
|
||||
}
|
||||
|
||||
// Disregard error, since it cannot be thrown if Count is > 0 and allowNaN is false, else NaN is accepted
|
||||
description.Std, _ = StandardDeviation(input)
|
||||
description.Max, _ = Max(input)
|
||||
description.Min, _ = Min(input)
|
||||
description.Mean, _ = Mean(input)
|
||||
|
||||
if percentiles != nil {
|
||||
for _, percentile := range *percentiles {
|
||||
if value, err := percentileFunc(input, percentile); err == nil || allowNaN {
|
||||
description.DescriptionPercentiles = append(description.DescriptionPercentiles, descriptionPercentile{Percentile: percentile, Value: value})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &description, nil
|
||||
}
|
||||
|
||||
/*
|
||||
Represents the Description instance in a string format with specified number of decimals
|
||||
|
||||
count 3
|
||||
mean 2.00
|
||||
std 0.82
|
||||
max 3.00
|
||||
min 1.00
|
||||
25.00% NaN
|
||||
50.00% 1.50
|
||||
75.00% 2.50
|
||||
NaN OK true
|
||||
*/
|
||||
func (d *Description) String(decimals int) string {
|
||||
var str string
|
||||
|
||||
str += fmt.Sprintf("count\t%d\n", d.Count)
|
||||
str += fmt.Sprintf("mean\t%.*f\n", decimals, d.Mean)
|
||||
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)
|
||||
for _, percentile := range d.DescriptionPercentiles {
|
||||
str += fmt.Sprintf("%.2f%%\t%.*f\n", percentile.Percentile, decimals, percentile.Value)
|
||||
}
|
||||
str += fmt.Sprintf("NaN OK\t%t", d.AllowedNaN)
|
||||
return str
|
||||
}
|
||||
57
vendor/github.com/montanaflynn/stats/deviation.go
generated
vendored
Normal file
57
vendor/github.com/montanaflynn/stats/deviation.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// MedianAbsoluteDeviation finds the median of the absolute deviations from the dataset median
|
||||
func MedianAbsoluteDeviation(input Float64Data) (mad float64, err error) {
|
||||
return MedianAbsoluteDeviationPopulation(input)
|
||||
}
|
||||
|
||||
// MedianAbsoluteDeviationPopulation finds the median of the absolute deviations from the population median
|
||||
func MedianAbsoluteDeviationPopulation(input Float64Data) (mad float64, err error) {
|
||||
if input.Len() == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
i := copyslice(input)
|
||||
m, _ := Median(i)
|
||||
|
||||
for key, value := range i {
|
||||
i[key] = math.Abs(value - m)
|
||||
}
|
||||
|
||||
return Median(i)
|
||||
}
|
||||
|
||||
// StandardDeviation the amount of variation in the dataset
|
||||
func StandardDeviation(input Float64Data) (sdev float64, err error) {
|
||||
return StandardDeviationPopulation(input)
|
||||
}
|
||||
|
||||
// StandardDeviationPopulation finds the amount of variation from the population
|
||||
func StandardDeviationPopulation(input Float64Data) (sdev float64, err error) {
|
||||
|
||||
if input.Len() == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
// Get the population variance
|
||||
vp, _ := PopulationVariance(input)
|
||||
|
||||
// Return the population standard deviation
|
||||
return math.Sqrt(vp), nil
|
||||
}
|
||||
|
||||
// StandardDeviationSample finds the amount of variation from a sample
|
||||
func StandardDeviationSample(input Float64Data) (sdev float64, err error) {
|
||||
|
||||
if input.Len() == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
// Get the sample variance
|
||||
vs, _ := SampleVariance(input)
|
||||
|
||||
// Return the sample standard deviation
|
||||
return math.Sqrt(vs), nil
|
||||
}
|
||||
91
vendor/github.com/montanaflynn/stats/distances.go
generated
vendored
Normal file
91
vendor/github.com/montanaflynn/stats/distances.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Validate data for distance calculation
|
||||
func validateData(dataPointX, dataPointY Float64Data) error {
|
||||
if len(dataPointX) == 0 || len(dataPointY) == 0 {
|
||||
return EmptyInputErr
|
||||
}
|
||||
|
||||
if len(dataPointX) != len(dataPointY) {
|
||||
return SizeErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChebyshevDistance computes the Chebyshev distance between two data sets
|
||||
func ChebyshevDistance(dataPointX, dataPointY Float64Data) (distance float64, err error) {
|
||||
err = validateData(dataPointX, dataPointY)
|
||||
if err != nil {
|
||||
return math.NaN(), err
|
||||
}
|
||||
var tempDistance float64
|
||||
for i := 0; i < len(dataPointY); i++ {
|
||||
tempDistance = math.Abs(dataPointX[i] - dataPointY[i])
|
||||
if distance < tempDistance {
|
||||
distance = tempDistance
|
||||
}
|
||||
}
|
||||
return distance, nil
|
||||
}
|
||||
|
||||
// EuclideanDistance computes the Euclidean distance between two data sets
|
||||
func EuclideanDistance(dataPointX, dataPointY Float64Data) (distance float64, err error) {
|
||||
|
||||
err = validateData(dataPointX, dataPointY)
|
||||
if err != nil {
|
||||
return math.NaN(), err
|
||||
}
|
||||
distance = 0
|
||||
for i := 0; i < len(dataPointX); i++ {
|
||||
distance = distance + ((dataPointX[i] - dataPointY[i]) * (dataPointX[i] - dataPointY[i]))
|
||||
}
|
||||
return math.Sqrt(distance), nil
|
||||
}
|
||||
|
||||
// ManhattanDistance computes the Manhattan distance between two data sets
|
||||
func ManhattanDistance(dataPointX, dataPointY Float64Data) (distance float64, err error) {
|
||||
err = validateData(dataPointX, dataPointY)
|
||||
if err != nil {
|
||||
return math.NaN(), err
|
||||
}
|
||||
distance = 0
|
||||
for i := 0; i < len(dataPointX); i++ {
|
||||
distance = distance + math.Abs(dataPointX[i]-dataPointY[i])
|
||||
}
|
||||
return distance, nil
|
||||
}
|
||||
|
||||
// MinkowskiDistance computes the Minkowski distance between two data sets
|
||||
//
|
||||
// Arguments:
|
||||
//
|
||||
// dataPointX: First set of data points
|
||||
// dataPointY: Second set of data points. Length of both data
|
||||
// sets must be equal.
|
||||
// lambda: aka p or city blocks; With lambda = 1
|
||||
// returned distance is manhattan distance and
|
||||
// lambda = 2; it is euclidean distance. Lambda
|
||||
// reaching to infinite - distance would be chebysev
|
||||
// distance.
|
||||
//
|
||||
// Return:
|
||||
//
|
||||
// Distance or error
|
||||
func MinkowskiDistance(dataPointX, dataPointY Float64Data, lambda float64) (distance float64, err error) {
|
||||
err = validateData(dataPointX, dataPointY)
|
||||
if err != nil {
|
||||
return math.NaN(), err
|
||||
}
|
||||
for i := 0; i < len(dataPointY); i++ {
|
||||
distance = distance + math.Pow(math.Abs(dataPointX[i]-dataPointY[i]), lambda)
|
||||
}
|
||||
distance = math.Pow(distance, 1/lambda)
|
||||
if math.IsInf(distance, 1) {
|
||||
return math.NaN(), InfValue
|
||||
}
|
||||
return distance, nil
|
||||
}
|
||||
23
vendor/github.com/montanaflynn/stats/doc.go
generated
vendored
Normal file
23
vendor/github.com/montanaflynn/stats/doc.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
Package stats is a well tested and comprehensive
|
||||
statistics library package with no dependencies.
|
||||
|
||||
Example Usage:
|
||||
|
||||
// start with some source data to use
|
||||
data := []float64{1.0, 2.1, 3.2, 4.823, 4.1, 5.8}
|
||||
|
||||
// you could also use different types like this
|
||||
// data := stats.LoadRawData([]int{1, 2, 3, 4, 5})
|
||||
// data := stats.LoadRawData([]interface{}{1.1, "2", 3})
|
||||
// etc...
|
||||
|
||||
median, _ := stats.Median(data)
|
||||
fmt.Println(median) // 3.65
|
||||
|
||||
roundedMedian, _ := stats.Round(median, 0)
|
||||
fmt.Println(roundedMedian) // 4
|
||||
|
||||
MIT License Copyright (c) 2014-2020 Montana Flynn (https://montanaflynn.com)
|
||||
*/
|
||||
package stats
|
||||
31
vendor/github.com/montanaflynn/stats/entropy.go
generated
vendored
Normal file
31
vendor/github.com/montanaflynn/stats/entropy.go
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// Entropy provides calculation of the entropy
|
||||
func Entropy(input Float64Data) (float64, error) {
|
||||
input, err := normalize(input)
|
||||
if err != nil {
|
||||
return math.NaN(), err
|
||||
}
|
||||
var result float64
|
||||
for i := 0; i < input.Len(); i++ {
|
||||
v := input.Get(i)
|
||||
if v == 0 {
|
||||
continue
|
||||
}
|
||||
result += (v * math.Log(v))
|
||||
}
|
||||
return -result, nil
|
||||
}
|
||||
|
||||
func normalize(input Float64Data) (Float64Data, error) {
|
||||
sum, err := input.Sum()
|
||||
if err != nil {
|
||||
return Float64Data{}, err
|
||||
}
|
||||
for i := 0; i < input.Len(); i++ {
|
||||
input[i] = input[i] / sum
|
||||
}
|
||||
return input, nil
|
||||
}
|
||||
35
vendor/github.com/montanaflynn/stats/errors.go
generated
vendored
Normal file
35
vendor/github.com/montanaflynn/stats/errors.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
package stats
|
||||
|
||||
type statsError struct {
|
||||
err string
|
||||
}
|
||||
|
||||
func (s statsError) Error() string {
|
||||
return s.err
|
||||
}
|
||||
|
||||
func (s statsError) String() string {
|
||||
return s.err
|
||||
}
|
||||
|
||||
// These are the package-wide error values.
|
||||
// All error identification should use these values.
|
||||
// https://github.com/golang/go/wiki/Errors#naming
|
||||
var (
|
||||
// ErrEmptyInput Input must not be empty
|
||||
ErrEmptyInput = statsError{"Input must not be empty."}
|
||||
// ErrNaN Not a number
|
||||
ErrNaN = statsError{"Not a number."}
|
||||
// ErrNegative Must not contain negative values
|
||||
ErrNegative = statsError{"Must not contain negative values."}
|
||||
// ErrZero Must not contain zero values
|
||||
ErrZero = statsError{"Must not contain zero values."}
|
||||
// ErrBounds Input is outside of range
|
||||
ErrBounds = statsError{"Input is outside of range."}
|
||||
// ErrSize Must be the same length
|
||||
ErrSize = statsError{"Must be the same length."}
|
||||
// ErrInfValue Value is infinite
|
||||
ErrInfValue = statsError{"Value is infinite."}
|
||||
// ErrYCoord Y Value must be greater than zero
|
||||
ErrYCoord = statsError{"Y Value must be greater than zero."}
|
||||
)
|
||||
42
vendor/github.com/montanaflynn/stats/geometric_distribution.go
generated
vendored
Normal file
42
vendor/github.com/montanaflynn/stats/geometric_distribution.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// ProbGeom generates the probability for a geometric random variable
|
||||
// with parameter p to achieve success in the interval of [a, b] trials
|
||||
// See https://en.wikipedia.org/wiki/Geometric_distribution for more information
|
||||
func ProbGeom(a int, b int, p float64) (prob float64, err error) {
|
||||
if (a > b) || (a < 1) {
|
||||
return math.NaN(), ErrBounds
|
||||
}
|
||||
|
||||
prob = 0
|
||||
q := 1 - p // probability of failure
|
||||
|
||||
for k := a + 1; k <= b; k++ {
|
||||
prob = prob + p*math.Pow(q, float64(k-1))
|
||||
}
|
||||
|
||||
return prob, nil
|
||||
}
|
||||
|
||||
// ProbGeom generates the expectation or average number of trials
|
||||
// for a geometric random variable with parameter p
|
||||
func ExpGeom(p float64) (exp float64, err error) {
|
||||
if (p > 1) || (p < 0) {
|
||||
return math.NaN(), ErrNegative
|
||||
}
|
||||
|
||||
return 1 / p, nil
|
||||
}
|
||||
|
||||
// ProbGeom generates the variance for number for a
|
||||
// geometric random variable with parameter p
|
||||
func VarGeom(p float64) (exp float64, err error) {
|
||||
if (p > 1) || (p < 0) {
|
||||
return math.NaN(), ErrNegative
|
||||
}
|
||||
return (1 - p) / math.Pow(p, 2), nil
|
||||
}
|
||||
49
vendor/github.com/montanaflynn/stats/legacy.go
generated
vendored
Normal file
49
vendor/github.com/montanaflynn/stats/legacy.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package stats
|
||||
|
||||
// VarP is a shortcut to PopulationVariance
|
||||
func VarP(input Float64Data) (sdev float64, err error) {
|
||||
return PopulationVariance(input)
|
||||
}
|
||||
|
||||
// VarS is a shortcut to SampleVariance
|
||||
func VarS(input Float64Data) (sdev float64, err error) {
|
||||
return SampleVariance(input)
|
||||
}
|
||||
|
||||
// StdDevP is a shortcut to StandardDeviationPopulation
|
||||
func StdDevP(input Float64Data) (sdev float64, err error) {
|
||||
return StandardDeviationPopulation(input)
|
||||
}
|
||||
|
||||
// StdDevS is a shortcut to StandardDeviationSample
|
||||
func StdDevS(input Float64Data) (sdev float64, err error) {
|
||||
return StandardDeviationSample(input)
|
||||
}
|
||||
|
||||
// LinReg is a shortcut to LinearRegression
|
||||
func LinReg(s []Coordinate) (regressions []Coordinate, err error) {
|
||||
return LinearRegression(s)
|
||||
}
|
||||
|
||||
// ExpReg is a shortcut to ExponentialRegression
|
||||
func ExpReg(s []Coordinate) (regressions []Coordinate, err error) {
|
||||
return ExponentialRegression(s)
|
||||
}
|
||||
|
||||
// LogReg is a shortcut to LogarithmicRegression
|
||||
func LogReg(s []Coordinate) (regressions []Coordinate, err error) {
|
||||
return LogarithmicRegression(s)
|
||||
}
|
||||
|
||||
// Legacy error names that didn't start with Err
|
||||
var (
|
||||
EmptyInputErr = ErrEmptyInput
|
||||
NaNErr = ErrNaN
|
||||
NegativeErr = ErrNegative
|
||||
ZeroErr = ErrZero
|
||||
BoundsErr = ErrBounds
|
||||
SizeErr = ErrSize
|
||||
InfValue = ErrInfValue
|
||||
YCoordErr = ErrYCoord
|
||||
EmptyInput = ErrEmptyInput
|
||||
)
|
||||
199
vendor/github.com/montanaflynn/stats/load.go
generated
vendored
Normal file
199
vendor/github.com/montanaflynn/stats/load.go
generated
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LoadRawData parses and converts a slice of mixed data types to floats
|
||||
func LoadRawData(raw interface{}) (f Float64Data) {
|
||||
var r []interface{}
|
||||
var s Float64Data
|
||||
|
||||
switch t := raw.(type) {
|
||||
case []interface{}:
|
||||
r = t
|
||||
case []uint:
|
||||
for _, v := range t {
|
||||
s = append(s, float64(v))
|
||||
}
|
||||
return s
|
||||
case []uint8:
|
||||
for _, v := range t {
|
||||
s = append(s, float64(v))
|
||||
}
|
||||
return s
|
||||
case []uint16:
|
||||
for _, v := range t {
|
||||
s = append(s, float64(v))
|
||||
}
|
||||
return s
|
||||
case []uint32:
|
||||
for _, v := range t {
|
||||
s = append(s, float64(v))
|
||||
}
|
||||
return s
|
||||
case []uint64:
|
||||
for _, v := range t {
|
||||
s = append(s, float64(v))
|
||||
}
|
||||
return s
|
||||
case []bool:
|
||||
for _, v := range t {
|
||||
if v {
|
||||
s = append(s, 1.0)
|
||||
} else {
|
||||
s = append(s, 0.0)
|
||||
}
|
||||
}
|
||||
return s
|
||||
case []float64:
|
||||
return Float64Data(t)
|
||||
case []int:
|
||||
for _, v := range t {
|
||||
s = append(s, float64(v))
|
||||
}
|
||||
return s
|
||||
case []int8:
|
||||
for _, v := range t {
|
||||
s = append(s, float64(v))
|
||||
}
|
||||
return s
|
||||
case []int16:
|
||||
for _, v := range t {
|
||||
s = append(s, float64(v))
|
||||
}
|
||||
return s
|
||||
case []int32:
|
||||
for _, v := range t {
|
||||
s = append(s, float64(v))
|
||||
}
|
||||
return s
|
||||
case []int64:
|
||||
for _, v := range t {
|
||||
s = append(s, float64(v))
|
||||
}
|
||||
return s
|
||||
case []string:
|
||||
for _, v := range t {
|
||||
r = append(r, v)
|
||||
}
|
||||
case []time.Duration:
|
||||
for _, v := range t {
|
||||
r = append(r, v)
|
||||
}
|
||||
case map[int]int:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, float64(t[i]))
|
||||
}
|
||||
return s
|
||||
case map[int]int8:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, float64(t[i]))
|
||||
}
|
||||
return s
|
||||
case map[int]int16:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, float64(t[i]))
|
||||
}
|
||||
return s
|
||||
case map[int]int32:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, float64(t[i]))
|
||||
}
|
||||
return s
|
||||
case map[int]int64:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, float64(t[i]))
|
||||
}
|
||||
return s
|
||||
case map[int]string:
|
||||
for i := 0; i < len(t); i++ {
|
||||
r = append(r, t[i])
|
||||
}
|
||||
case map[int]uint:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, float64(t[i]))
|
||||
}
|
||||
return s
|
||||
case map[int]uint8:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, float64(t[i]))
|
||||
}
|
||||
return s
|
||||
case map[int]uint16:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, float64(t[i]))
|
||||
}
|
||||
return s
|
||||
case map[int]uint32:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, float64(t[i]))
|
||||
}
|
||||
return s
|
||||
case map[int]uint64:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, float64(t[i]))
|
||||
}
|
||||
return s
|
||||
case map[int]bool:
|
||||
for i := 0; i < len(t); i++ {
|
||||
if t[i] {
|
||||
s = append(s, 1.0)
|
||||
} else {
|
||||
s = append(s, 0.0)
|
||||
}
|
||||
}
|
||||
return s
|
||||
case map[int]float64:
|
||||
for i := 0; i < len(t); i++ {
|
||||
s = append(s, t[i])
|
||||
}
|
||||
return s
|
||||
case map[int]time.Duration:
|
||||
for i := 0; i < len(t); i++ {
|
||||
r = append(r, t[i])
|
||||
}
|
||||
case string:
|
||||
for _, v := range strings.Fields(t) {
|
||||
r = append(r, v)
|
||||
}
|
||||
case io.Reader:
|
||||
scanner := bufio.NewScanner(t)
|
||||
for scanner.Scan() {
|
||||
l := scanner.Text()
|
||||
for _, v := range strings.Fields(l) {
|
||||
r = append(r, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range r {
|
||||
switch t := v.(type) {
|
||||
case int:
|
||||
a := float64(t)
|
||||
f = append(f, a)
|
||||
case uint:
|
||||
f = append(f, float64(t))
|
||||
case float64:
|
||||
f = append(f, t)
|
||||
case string:
|
||||
fl, err := strconv.ParseFloat(t, 64)
|
||||
if err == nil {
|
||||
f = append(f, fl)
|
||||
}
|
||||
case bool:
|
||||
if t {
|
||||
f = append(f, 1.0)
|
||||
} else {
|
||||
f = append(f, 0.0)
|
||||
}
|
||||
case time.Duration:
|
||||
f = append(f, float64(t))
|
||||
}
|
||||
}
|
||||
return f
|
||||
}
|
||||
26
vendor/github.com/montanaflynn/stats/max.go
generated
vendored
Normal file
26
vendor/github.com/montanaflynn/stats/max.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Max finds the highest number in a slice
|
||||
func Max(input Float64Data) (max float64, err error) {
|
||||
|
||||
// Return an error if there are no numbers
|
||||
if input.Len() == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
// Get the first value as the starting point
|
||||
max = input.Get(0)
|
||||
|
||||
// Loop and replace higher values
|
||||
for i := 1; i < input.Len(); i++ {
|
||||
if input.Get(i) > max {
|
||||
max = input.Get(i)
|
||||
}
|
||||
}
|
||||
|
||||
return max, nil
|
||||
}
|
||||
60
vendor/github.com/montanaflynn/stats/mean.go
generated
vendored
Normal file
60
vendor/github.com/montanaflynn/stats/mean.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// Mean gets the average of a slice of numbers
|
||||
func Mean(input Float64Data) (float64, error) {
|
||||
|
||||
if input.Len() == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
sum, _ := input.Sum()
|
||||
|
||||
return sum / float64(input.Len()), nil
|
||||
}
|
||||
|
||||
// GeometricMean gets the geometric mean for a slice of numbers
|
||||
func GeometricMean(input Float64Data) (float64, error) {
|
||||
|
||||
l := input.Len()
|
||||
if l == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
// Get the product of all the numbers
|
||||
var p float64
|
||||
for _, n := range input {
|
||||
if p == 0 {
|
||||
p = n
|
||||
} else {
|
||||
p *= n
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the geometric mean
|
||||
return math.Pow(p, 1/float64(l)), nil
|
||||
}
|
||||
|
||||
// HarmonicMean gets the harmonic mean for a slice of numbers
|
||||
func HarmonicMean(input Float64Data) (float64, error) {
|
||||
|
||||
l := input.Len()
|
||||
if l == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
// Get the sum of all the numbers reciprocals and return an
|
||||
// error for values that cannot be included in harmonic mean
|
||||
var p float64
|
||||
for _, n := range input {
|
||||
if n < 0 {
|
||||
return math.NaN(), NegativeErr
|
||||
} else if n == 0 {
|
||||
return math.NaN(), ZeroErr
|
||||
}
|
||||
p += (1 / n)
|
||||
}
|
||||
|
||||
return float64(l) / p, nil
|
||||
}
|
||||
25
vendor/github.com/montanaflynn/stats/median.go
generated
vendored
Normal file
25
vendor/github.com/montanaflynn/stats/median.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// Median gets the median number in a slice of numbers
|
||||
func Median(input Float64Data) (median float64, err error) {
|
||||
|
||||
// Start by sorting a copy of the slice
|
||||
c := sortedCopy(input)
|
||||
|
||||
// No math is needed if there are no numbers
|
||||
// For even numbers we add the two middle numbers
|
||||
// and divide by two using the mean function above
|
||||
// For odd numbers we just use the middle number
|
||||
l := len(c)
|
||||
if l == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
} else if l%2 == 0 {
|
||||
median, _ = Mean(c[l/2-1 : l/2+1])
|
||||
} else {
|
||||
median = c[l/2]
|
||||
}
|
||||
|
||||
return median, nil
|
||||
}
|
||||
26
vendor/github.com/montanaflynn/stats/min.go
generated
vendored
Normal file
26
vendor/github.com/montanaflynn/stats/min.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// Min finds the lowest number in a set of data
|
||||
func Min(input Float64Data) (min float64, err error) {
|
||||
|
||||
// Get the count of numbers in the slice
|
||||
l := input.Len()
|
||||
|
||||
// Return an error if there are no numbers
|
||||
if l == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
// Get the first value as the starting point
|
||||
min = input.Get(0)
|
||||
|
||||
// Iterate until done checking for a lower value
|
||||
for i := 1; i < l; i++ {
|
||||
if input.Get(i) < min {
|
||||
min = input.Get(i)
|
||||
}
|
||||
}
|
||||
return min, nil
|
||||
}
|
||||
47
vendor/github.com/montanaflynn/stats/mode.go
generated
vendored
Normal file
47
vendor/github.com/montanaflynn/stats/mode.go
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
package stats
|
||||
|
||||
// Mode gets the mode [most frequent value(s)] of a slice of float64s
|
||||
func Mode(input Float64Data) (mode []float64, err error) {
|
||||
// Return the input if there's only one number
|
||||
l := input.Len()
|
||||
if l == 1 {
|
||||
return input, nil
|
||||
} else if l == 0 {
|
||||
return nil, EmptyInputErr
|
||||
}
|
||||
|
||||
c := sortedCopyDif(input)
|
||||
// Traverse sorted array,
|
||||
// tracking the longest repeating sequence
|
||||
mode = make([]float64, 5)
|
||||
cnt, maxCnt := 1, 1
|
||||
for i := 1; i < l; i++ {
|
||||
switch {
|
||||
case c[i] == c[i-1]:
|
||||
cnt++
|
||||
case cnt == maxCnt && maxCnt != 1:
|
||||
mode = append(mode, c[i-1])
|
||||
cnt = 1
|
||||
case cnt > maxCnt:
|
||||
mode = append(mode[:0], c[i-1])
|
||||
maxCnt, cnt = cnt, 1
|
||||
default:
|
||||
cnt = 1
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case cnt == maxCnt:
|
||||
mode = append(mode, c[l-1])
|
||||
case cnt > maxCnt:
|
||||
mode = append(mode[:0], c[l-1])
|
||||
maxCnt = cnt
|
||||
}
|
||||
|
||||
// Since length must be greater than 1,
|
||||
// check for slices of distinct values
|
||||
if maxCnt == 1 || len(mode)*maxCnt == l && maxCnt != l {
|
||||
return Float64Data{}, nil
|
||||
}
|
||||
|
||||
return mode, nil
|
||||
}
|
||||
254
vendor/github.com/montanaflynn/stats/norm.go
generated
vendored
Normal file
254
vendor/github.com/montanaflynn/stats/norm.go
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var toReturn []float64
|
||||
for i := 0; i < size; i++ {
|
||||
toReturn = append(toReturn, NormPpf(rand.Float64(), loc, scale))
|
||||
}
|
||||
return toReturn
|
||||
}
|
||||
|
||||
// NormBoxMullerRvs generates random variates using the Box–Muller transform.
|
||||
// For more information please visit: http://mathworld.wolfram.com/Box-MullerTransformation.html
|
||||
func NormBoxMullerRvs(loc float64, scale float64, size int) []float64 {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var toReturn []float64
|
||||
for i := 0; i < int(float64(size/2)+float64(size%2)); i++ {
|
||||
// u1 and u2 are uniformly distributed random numbers between 0 and 1.
|
||||
u1 := rand.Float64()
|
||||
u2 := rand.Float64()
|
||||
// x1 and x2 are normally distributed random numbers.
|
||||
x1 := loc + (scale * (math.Sqrt(-2*math.Log(u1)) * math.Cos(2*math.Pi*u2)))
|
||||
toReturn = append(toReturn, x1)
|
||||
if (i+1)*2 <= size {
|
||||
x2 := loc + (scale * (math.Sqrt(-2*math.Log(u1)) * math.Sin(2*math.Pi*u2)))
|
||||
toReturn = append(toReturn, x2)
|
||||
}
|
||||
}
|
||||
return toReturn
|
||||
}
|
||||
|
||||
// NormPdf is the probability density function.
|
||||
func NormPdf(x float64, loc float64, scale float64) float64 {
|
||||
return (math.Pow(math.E, -(math.Pow(x-loc, 2))/(2*math.Pow(scale, 2)))) / (scale * math.Sqrt(2*math.Pi))
|
||||
}
|
||||
|
||||
// NormLogPdf is the log of the probability density function.
|
||||
func NormLogPdf(x float64, loc float64, scale float64) float64 {
|
||||
return math.Log((math.Pow(math.E, -(math.Pow(x-loc, 2))/(2*math.Pow(scale, 2)))) / (scale * math.Sqrt(2*math.Pi)))
|
||||
}
|
||||
|
||||
// NormCdf is the cumulative distribution function.
|
||||
func NormCdf(x float64, loc float64, scale float64) float64 {
|
||||
return 0.5 * (1 + math.Erf((x-loc)/(scale*math.Sqrt(2))))
|
||||
}
|
||||
|
||||
// NormLogCdf is the log of the cumulative distribution function.
|
||||
func NormLogCdf(x float64, loc float64, scale float64) float64 {
|
||||
return math.Log(0.5 * (1 + math.Erf((x-loc)/(scale*math.Sqrt(2)))))
|
||||
}
|
||||
|
||||
// NormSf is the survival function (also defined as 1 - cdf, but sf is sometimes more accurate).
|
||||
func NormSf(x float64, loc float64, scale float64) float64 {
|
||||
return 1 - 0.5*(1+math.Erf((x-loc)/(scale*math.Sqrt(2))))
|
||||
}
|
||||
|
||||
// NormLogSf is the log of the survival function.
|
||||
func NormLogSf(x float64, loc float64, scale float64) float64 {
|
||||
return math.Log(1 - 0.5*(1+math.Erf((x-loc)/(scale*math.Sqrt(2)))))
|
||||
}
|
||||
|
||||
// NormPpf is the point percentile function.
|
||||
// This is based on Peter John Acklam's inverse normal CDF.
|
||||
// algorithm: http://home.online.no/~pjacklam/notes/invnorm/ (no longer visible).
|
||||
// For more information please visit: https://stackedboxes.org/2017/05/01/acklams-normal-quantile-function/
|
||||
func NormPpf(p float64, loc float64, scale float64) (x float64) {
|
||||
const (
|
||||
a1 = -3.969683028665376e+01
|
||||
a2 = 2.209460984245205e+02
|
||||
a3 = -2.759285104469687e+02
|
||||
a4 = 1.383577518672690e+02
|
||||
a5 = -3.066479806614716e+01
|
||||
a6 = 2.506628277459239e+00
|
||||
|
||||
b1 = -5.447609879822406e+01
|
||||
b2 = 1.615858368580409e+02
|
||||
b3 = -1.556989798598866e+02
|
||||
b4 = 6.680131188771972e+01
|
||||
b5 = -1.328068155288572e+01
|
||||
|
||||
c1 = -7.784894002430293e-03
|
||||
c2 = -3.223964580411365e-01
|
||||
c3 = -2.400758277161838e+00
|
||||
c4 = -2.549732539343734e+00
|
||||
c5 = 4.374664141464968e+00
|
||||
c6 = 2.938163982698783e+00
|
||||
|
||||
d1 = 7.784695709041462e-03
|
||||
d2 = 3.224671290700398e-01
|
||||
d3 = 2.445134137142996e+00
|
||||
d4 = 3.754408661907416e+00
|
||||
|
||||
plow = 0.02425
|
||||
phigh = 1 - plow
|
||||
)
|
||||
|
||||
if p < 0 || p > 1 {
|
||||
return math.NaN()
|
||||
} else if p == 0 {
|
||||
return -math.Inf(0)
|
||||
} else if p == 1 {
|
||||
return math.Inf(0)
|
||||
}
|
||||
|
||||
if p < plow {
|
||||
q := math.Sqrt(-2 * math.Log(p))
|
||||
x = (((((c1*q+c2)*q+c3)*q+c4)*q+c5)*q + c6) /
|
||||
((((d1*q+d2)*q+d3)*q+d4)*q + 1)
|
||||
} else if phigh < p {
|
||||
q := math.Sqrt(-2 * math.Log(1-p))
|
||||
x = -(((((c1*q+c2)*q+c3)*q+c4)*q+c5)*q + c6) /
|
||||
((((d1*q+d2)*q+d3)*q+d4)*q + 1)
|
||||
} else {
|
||||
q := p - 0.5
|
||||
r := q * q
|
||||
x = (((((a1*r+a2)*r+a3)*r+a4)*r+a5)*r + a6) * q /
|
||||
(((((b1*r+b2)*r+b3)*r+b4)*r+b5)*r + 1)
|
||||
}
|
||||
|
||||
e := 0.5*math.Erfc(-x/math.Sqrt2) - p
|
||||
u := e * math.Sqrt(2*math.Pi) * math.Exp(x*x/2)
|
||||
x = x - u/(1+x*u/2)
|
||||
|
||||
return x*scale + loc
|
||||
}
|
||||
|
||||
// NormIsf is the inverse survival function (inverse of sf).
|
||||
func NormIsf(p float64, loc float64, scale float64) (x float64) {
|
||||
if -NormPpf(p, loc, scale) == 0 {
|
||||
return 0
|
||||
}
|
||||
return -NormPpf(p, loc, scale)
|
||||
}
|
||||
|
||||
// NormMoment approximates the non-central (raw) moment of order n.
|
||||
// For more information please visit: https://math.stackexchange.com/questions/1945448/methods-for-finding-raw-moments-of-the-normal-distribution
|
||||
func NormMoment(n int, loc float64, scale float64) float64 {
|
||||
toReturn := 0.0
|
||||
for i := 0; i < n+1; i++ {
|
||||
if (n-i)%2 == 0 {
|
||||
toReturn += float64(Ncr(n, i)) * (math.Pow(loc, float64(i))) * (math.Pow(scale, float64(n-i))) *
|
||||
(float64(factorial(n-i)) / ((math.Pow(2.0, float64((n-i)/2))) *
|
||||
float64(factorial((n-i)/2))))
|
||||
}
|
||||
}
|
||||
return toReturn
|
||||
}
|
||||
|
||||
// NormStats returns the mean, variance, skew, and/or kurtosis.
|
||||
// Mean(‘m’), variance(‘v’), skew(‘s’), and/or kurtosis(‘k’).
|
||||
// Takes string containing any of 'mvsk'.
|
||||
// Returns array of m v s k in that order.
|
||||
func NormStats(loc float64, scale float64, moments string) []float64 {
|
||||
var toReturn []float64
|
||||
if strings.ContainsAny(moments, "m") {
|
||||
toReturn = append(toReturn, loc)
|
||||
}
|
||||
if strings.ContainsAny(moments, "v") {
|
||||
toReturn = append(toReturn, math.Pow(scale, 2))
|
||||
}
|
||||
if strings.ContainsAny(moments, "s") {
|
||||
toReturn = append(toReturn, 0.0)
|
||||
}
|
||||
if strings.ContainsAny(moments, "k") {
|
||||
toReturn = append(toReturn, 0.0)
|
||||
}
|
||||
return toReturn
|
||||
}
|
||||
|
||||
// NormEntropy is the differential entropy of the RV.
|
||||
func NormEntropy(loc float64, scale float64) float64 {
|
||||
return math.Log(scale * math.Sqrt(2*math.Pi*math.E))
|
||||
}
|
||||
|
||||
// NormFit returns the maximum likelihood estimators for the Normal Distribution.
|
||||
// Takes array of float64 values.
|
||||
// Returns array of Mean followed by Standard Deviation.
|
||||
func NormFit(data []float64) [2]float64 {
|
||||
sum := 0.00
|
||||
for i := 0; i < len(data); i++ {
|
||||
sum += data[i]
|
||||
}
|
||||
mean := sum / float64(len(data))
|
||||
stdNumerator := 0.00
|
||||
for i := 0; i < len(data); i++ {
|
||||
stdNumerator += math.Pow(data[i]-mean, 2)
|
||||
}
|
||||
return [2]float64{mean, math.Sqrt((stdNumerator) / (float64(len(data))))}
|
||||
}
|
||||
|
||||
// NormMedian is the median of the distribution.
|
||||
func NormMedian(loc float64, scale float64) float64 {
|
||||
return loc
|
||||
}
|
||||
|
||||
// NormMean is the mean/expected value of the distribution.
|
||||
func NormMean(loc float64, scale float64) float64 {
|
||||
return loc
|
||||
}
|
||||
|
||||
// NormVar is the variance of the distribution.
|
||||
func NormVar(loc float64, scale float64) float64 {
|
||||
return math.Pow(scale, 2)
|
||||
}
|
||||
|
||||
// NormStd is the standard deviation of the distribution.
|
||||
func NormStd(loc float64, scale float64) float64 {
|
||||
return scale
|
||||
}
|
||||
|
||||
// NormInterval finds endpoints of the range that contains alpha percent of the distribution.
|
||||
func NormInterval(alpha float64, loc float64, scale float64) [2]float64 {
|
||||
q1 := (1.0 - alpha) / 2
|
||||
q2 := (1.0 + alpha) / 2
|
||||
a := NormPpf(q1, loc, scale)
|
||||
b := NormPpf(q2, loc, scale)
|
||||
return [2]float64{a, b}
|
||||
}
|
||||
|
||||
// factorial is the naive factorial algorithm.
|
||||
func factorial(x int) int {
|
||||
if x == 0 {
|
||||
return 1
|
||||
}
|
||||
return x * factorial(x-1)
|
||||
}
|
||||
|
||||
// Ncr is an N choose R algorithm.
|
||||
// Aaron Cannon's algorithm.
|
||||
func Ncr(n, r int) int {
|
||||
if n <= 1 || r == 0 || n == r {
|
||||
return 1
|
||||
}
|
||||
if newR := n - r; newR < r {
|
||||
r = newR
|
||||
}
|
||||
if r == 1 {
|
||||
return n
|
||||
}
|
||||
ret := int(n - r + 1)
|
||||
for i, j := ret+1, int(2); j <= r; i, j = i+1, j+1 {
|
||||
ret = ret * i / j
|
||||
}
|
||||
return ret
|
||||
}
|
||||
44
vendor/github.com/montanaflynn/stats/outlier.go
generated
vendored
Normal file
44
vendor/github.com/montanaflynn/stats/outlier.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package stats
|
||||
|
||||
// Outliers holds mild and extreme outliers found in data
|
||||
type Outliers struct {
|
||||
Mild Float64Data
|
||||
Extreme Float64Data
|
||||
}
|
||||
|
||||
// QuartileOutliers finds the mild and extreme outliers
|
||||
func QuartileOutliers(input Float64Data) (Outliers, error) {
|
||||
if input.Len() == 0 {
|
||||
return Outliers{}, EmptyInputErr
|
||||
}
|
||||
|
||||
// Start by sorting a copy of the slice
|
||||
copy := sortedCopy(input)
|
||||
|
||||
// Calculate the quartiles and interquartile range
|
||||
qs, _ := Quartile(copy)
|
||||
iqr, _ := InterQuartileRange(copy)
|
||||
|
||||
// Calculate the lower and upper inner and outer fences
|
||||
lif := qs.Q1 - (1.5 * iqr)
|
||||
uif := qs.Q3 + (1.5 * iqr)
|
||||
lof := qs.Q1 - (3 * iqr)
|
||||
uof := qs.Q3 + (3 * iqr)
|
||||
|
||||
// Find the data points that are outside of the
|
||||
// inner and upper fences and add them to mild
|
||||
// and extreme outlier slices
|
||||
var mild Float64Data
|
||||
var extreme Float64Data
|
||||
for _, v := range copy {
|
||||
|
||||
if v < lof || v > uof {
|
||||
extreme = append(extreme, v)
|
||||
} else if v < lif || v > uif {
|
||||
mild = append(mild, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap them into our struct
|
||||
return Outliers{mild, extreme}, nil
|
||||
}
|
||||
86
vendor/github.com/montanaflynn/stats/percentile.go
generated
vendored
Normal file
86
vendor/github.com/montanaflynn/stats/percentile.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
// Percentile finds the relative standing in a slice of floats
|
||||
func Percentile(input Float64Data, percent float64) (percentile float64, err error) {
|
||||
length := input.Len()
|
||||
if length == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
if length == 1 {
|
||||
return input[0], nil
|
||||
}
|
||||
|
||||
if percent <= 0 || percent > 100 {
|
||||
return math.NaN(), BoundsErr
|
||||
}
|
||||
|
||||
// Start by sorting a copy of the slice
|
||||
c := sortedCopy(input)
|
||||
|
||||
// Multiply percent by length of input
|
||||
index := (percent / 100) * float64(len(c))
|
||||
|
||||
// Check if the index is a whole number
|
||||
if index == float64(int64(index)) {
|
||||
|
||||
// Convert float to int
|
||||
i := int(index)
|
||||
|
||||
// Find the value at the index
|
||||
percentile = c[i-1]
|
||||
|
||||
} else if index > 1 {
|
||||
|
||||
// Convert float to int via truncation
|
||||
i := int(index)
|
||||
|
||||
// Find the average of the index and following values
|
||||
percentile, _ = Mean(Float64Data{c[i-1], c[i]})
|
||||
|
||||
} else {
|
||||
return math.NaN(), BoundsErr
|
||||
}
|
||||
|
||||
return percentile, nil
|
||||
|
||||
}
|
||||
|
||||
// PercentileNearestRank finds the relative standing in a slice of floats using the Nearest Rank method
|
||||
func PercentileNearestRank(input Float64Data, percent float64) (percentile float64, err error) {
|
||||
|
||||
// Find the length of items in the slice
|
||||
il := input.Len()
|
||||
|
||||
// Return an error for empty slices
|
||||
if il == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
// Return error for less than 0 or greater than 100 percentages
|
||||
if percent < 0 || percent > 100 {
|
||||
return math.NaN(), BoundsErr
|
||||
}
|
||||
|
||||
// Start by sorting a copy of the slice
|
||||
c := sortedCopy(input)
|
||||
|
||||
// Return the last item
|
||||
if percent == 100.0 {
|
||||
return c[il-1], nil
|
||||
}
|
||||
|
||||
// Find ordinal ranking
|
||||
or := int(math.Ceil(float64(il) * percent / 100))
|
||||
|
||||
// Return the item that is in the place of the ordinal rank
|
||||
if or == 0 {
|
||||
return c[0], nil
|
||||
}
|
||||
return c[or-1], nil
|
||||
|
||||
}
|
||||
74
vendor/github.com/montanaflynn/stats/quartile.go
generated
vendored
Normal file
74
vendor/github.com/montanaflynn/stats/quartile.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// Quartiles holds the three quartile points
|
||||
type Quartiles struct {
|
||||
Q1 float64
|
||||
Q2 float64
|
||||
Q3 float64
|
||||
}
|
||||
|
||||
// Quartile returns the three quartile points from a slice of data
|
||||
func Quartile(input Float64Data) (Quartiles, error) {
|
||||
|
||||
il := input.Len()
|
||||
if il == 0 {
|
||||
return Quartiles{}, EmptyInputErr
|
||||
}
|
||||
|
||||
// Start by sorting a copy of the slice
|
||||
copy := sortedCopy(input)
|
||||
|
||||
// Find the cutoff places depeding on if
|
||||
// the input slice length is even or odd
|
||||
var c1 int
|
||||
var c2 int
|
||||
if il%2 == 0 {
|
||||
c1 = il / 2
|
||||
c2 = il / 2
|
||||
} else {
|
||||
c1 = (il - 1) / 2
|
||||
c2 = c1 + 1
|
||||
}
|
||||
|
||||
// Find the Medians with the cutoff points
|
||||
Q1, _ := Median(copy[:c1])
|
||||
Q2, _ := Median(copy)
|
||||
Q3, _ := Median(copy[c2:])
|
||||
|
||||
return Quartiles{Q1, Q2, Q3}, nil
|
||||
|
||||
}
|
||||
|
||||
// InterQuartileRange finds the range between Q1 and Q3
|
||||
func InterQuartileRange(input Float64Data) (float64, error) {
|
||||
if input.Len() == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
qs, _ := Quartile(input)
|
||||
iqr := qs.Q3 - qs.Q1
|
||||
return iqr, nil
|
||||
}
|
||||
|
||||
// Midhinge finds the average of the first and third quartiles
|
||||
func Midhinge(input Float64Data) (float64, error) {
|
||||
if input.Len() == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
qs, _ := Quartile(input)
|
||||
mh := (qs.Q1 + qs.Q3) / 2
|
||||
return mh, nil
|
||||
}
|
||||
|
||||
// Trimean finds the average of the median and the midhinge
|
||||
func Trimean(input Float64Data) (float64, error) {
|
||||
if input.Len() == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
c := sortedCopy(input)
|
||||
q, _ := Quartile(c)
|
||||
|
||||
return (q.Q1 + (q.Q2 * 2) + q.Q3) / 4, nil
|
||||
}
|
||||
183
vendor/github.com/montanaflynn/stats/ranksum.go
generated
vendored
Normal file
183
vendor/github.com/montanaflynn/stats/ranksum.go
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
package stats
|
||||
|
||||
// import "math"
|
||||
//
|
||||
// // WilcoxonRankSum tests the null hypothesis that two sets
|
||||
// // of data are drawn from the same distribution. It does
|
||||
// // not handle ties between measurements in x and y.
|
||||
// //
|
||||
// // Parameters:
|
||||
// // data1 Float64Data: First set of data points.
|
||||
// // data2 Float64Data: Second set of data points.
|
||||
// // Length of both data samples must be equal.
|
||||
// //
|
||||
// // Return:
|
||||
// // statistic float64: The test statistic under the
|
||||
// // large-sample approximation that the
|
||||
// // rank sum statistic is normally distributed.
|
||||
// // pvalue float64: The two-sided p-value of the test
|
||||
// // err error: Any error from the input data parameters
|
||||
// //
|
||||
// // https://en.wikipedia.org/wiki/Wilcoxon_rank-sum_test
|
||||
// func WilcoxonRankSum(data1, data2 Float64Data) (float64, float64, error) {
|
||||
//
|
||||
// l1 := data1.Len()
|
||||
// l2 := data2.Len()
|
||||
//
|
||||
// if l1 == 0 || l2 == 0 {
|
||||
// return math.NaN(), math.NaN(), EmptyInputErr
|
||||
// }
|
||||
//
|
||||
// if l1 != l2 {
|
||||
// return math.NaN(), math.NaN(), SizeErr
|
||||
// }
|
||||
//
|
||||
// alldata := Float64Data{}
|
||||
// alldata = append(alldata, data1...)
|
||||
// alldata = append(alldata, data2...)
|
||||
//
|
||||
// // ranked :=
|
||||
//
|
||||
// return 0.0, 0.0, nil
|
||||
// }
|
||||
//
|
||||
// // x, y = map(np.asarray, (x, y))
|
||||
// // n1 = len(x)
|
||||
// // n2 = len(y)
|
||||
// // alldata = np.concatenate((x, y))
|
||||
// // ranked = rankdata(alldata)
|
||||
// // x = ranked[:n1]
|
||||
// // s = np.sum(x, axis=0)
|
||||
// // expected = n1 * (n1+n2+1) / 2.0
|
||||
// // z = (s - expected) / np.sqrt(n1*n2*(n1+n2+1)/12.0)
|
||||
// // prob = 2 * distributions.norm.sf(abs(z))
|
||||
// //
|
||||
// // return RanksumsResult(z, prob)
|
||||
//
|
||||
// // def rankdata(a, method='average'):
|
||||
// // """
|
||||
// // Assign ranks to data, dealing with ties appropriately.
|
||||
// // Ranks begin at 1. The `method` argument controls how ranks are assigned
|
||||
// // to equal values. See [1]_ for further discussion of ranking methods.
|
||||
// // Parameters
|
||||
// // ----------
|
||||
// // a : array_like
|
||||
// // The array of values to be ranked. The array is first flattened.
|
||||
// // method : str, optional
|
||||
// // The method used to assign ranks to tied elements.
|
||||
// // The options are 'average', 'min', 'max', 'dense' and 'ordinal'.
|
||||
// // 'average':
|
||||
// // The average of the ranks that would have been assigned to
|
||||
// // all the tied values is assigned to each value.
|
||||
// // 'min':
|
||||
// // The minimum of the ranks that would have been assigned to all
|
||||
// // the tied values is assigned to each value. (This is also
|
||||
// // referred to as "competition" ranking.)
|
||||
// // 'max':
|
||||
// // The maximum of the ranks that would have been assigned to all
|
||||
// // the tied values is assigned to each value.
|
||||
// // 'dense':
|
||||
// // Like 'min', but the rank of the next highest element is assigned
|
||||
// // the rank immediately after those assigned to the tied elements.
|
||||
// // 'ordinal':
|
||||
// // All values are given a distinct rank, corresponding to the order
|
||||
// // that the values occur in `a`.
|
||||
// // The default is 'average'.
|
||||
// // Returns
|
||||
// // -------
|
||||
// // ranks : ndarray
|
||||
// // An array of length equal to the size of `a`, containing rank
|
||||
// // scores.
|
||||
// // References
|
||||
// // ----------
|
||||
// // .. [1] "Ranking", https://en.wikipedia.org/wiki/Ranking
|
||||
// // Examples
|
||||
// // --------
|
||||
// // >>> from scipy.stats import rankdata
|
||||
// // >>> rankdata([0, 2, 3, 2])
|
||||
// // array([ 1. , 2.5, 4. , 2.5])
|
||||
// // """
|
||||
// //
|
||||
// // arr = np.ravel(np.asarray(a))
|
||||
// // algo = 'quicksort'
|
||||
// // sorter = np.argsort(arr, kind=algo)
|
||||
// //
|
||||
// // inv = np.empty(sorter.size, dtype=np.intp)
|
||||
// // inv[sorter] = np.arange(sorter.size, dtype=np.intp)
|
||||
// //
|
||||
// //
|
||||
// // arr = arr[sorter]
|
||||
// // obs = np.r_[True, arr[1:] != arr[:-1]]
|
||||
// // dense = obs.cumsum()[inv]
|
||||
// //
|
||||
// //
|
||||
// // # cumulative counts of each unique value
|
||||
// // count = np.r_[np.nonzero(obs)[0], len(obs)]
|
||||
// //
|
||||
// // # average method
|
||||
// // return .5 * (count[dense] + count[dense - 1] + 1)
|
||||
//
|
||||
// type rankable interface {
|
||||
// Len() int
|
||||
// RankEqual(int, int) bool
|
||||
// }
|
||||
//
|
||||
// func StandardRank(d rankable) []float64 {
|
||||
// r := make([]float64, d.Len())
|
||||
// var k int
|
||||
// for i := range r {
|
||||
// if i == 0 || !d.RankEqual(i, i-1) {
|
||||
// k = i + 1
|
||||
// }
|
||||
// r[i] = float64(k)
|
||||
// }
|
||||
// return r
|
||||
// }
|
||||
//
|
||||
// func ModifiedRank(d rankable) []float64 {
|
||||
// r := make([]float64, d.Len())
|
||||
// for i := range r {
|
||||
// k := i + 1
|
||||
// for j := i + 1; j < len(r) && d.RankEqual(i, j); j++ {
|
||||
// k = j + 1
|
||||
// }
|
||||
// r[i] = float64(k)
|
||||
// }
|
||||
// return r
|
||||
// }
|
||||
//
|
||||
// func DenseRank(d rankable) []float64 {
|
||||
// r := make([]float64, d.Len())
|
||||
// var k int
|
||||
// for i := range r {
|
||||
// if i == 0 || !d.RankEqual(i, i-1) {
|
||||
// k++
|
||||
// }
|
||||
// r[i] = float64(k)
|
||||
// }
|
||||
// return r
|
||||
// }
|
||||
//
|
||||
// func OrdinalRank(d rankable) []float64 {
|
||||
// r := make([]float64, d.Len())
|
||||
// for i := range r {
|
||||
// r[i] = float64(i + 1)
|
||||
// }
|
||||
// return r
|
||||
// }
|
||||
//
|
||||
// func FractionalRank(d rankable) []float64 {
|
||||
// r := make([]float64, d.Len())
|
||||
// for i := 0; i < len(r); {
|
||||
// var j int
|
||||
// f := float64(i + 1)
|
||||
// for j = i + 1; j < len(r) && d.RankEqual(i, j); j++ {
|
||||
// f += float64(j + 1)
|
||||
// }
|
||||
// f /= float64(j - i)
|
||||
// for ; i < j; i++ {
|
||||
// r[i] = f
|
||||
// }
|
||||
// }
|
||||
// return r
|
||||
// }
|
||||
113
vendor/github.com/montanaflynn/stats/regression.go
generated
vendored
Normal file
113
vendor/github.com/montanaflynn/stats/regression.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// Series is a container for a series of data
|
||||
type Series []Coordinate
|
||||
|
||||
// Coordinate holds the data in a series
|
||||
type Coordinate struct {
|
||||
X, Y float64
|
||||
}
|
||||
|
||||
// LinearRegression finds the least squares linear regression on data series
|
||||
func LinearRegression(s Series) (regressions Series, err error) {
|
||||
|
||||
if len(s) == 0 {
|
||||
return nil, EmptyInputErr
|
||||
}
|
||||
|
||||
// Placeholder for the math to be done
|
||||
var sum [5]float64
|
||||
|
||||
// Loop over data keeping index in place
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
sum[0] += s[i].X
|
||||
sum[1] += s[i].Y
|
||||
sum[2] += s[i].X * s[i].X
|
||||
sum[3] += s[i].X * s[i].Y
|
||||
sum[4] += s[i].Y * s[i].Y
|
||||
}
|
||||
|
||||
// Find gradient and intercept
|
||||
f := float64(i)
|
||||
gradient := (f*sum[3] - sum[0]*sum[1]) / (f*sum[2] - sum[0]*sum[0])
|
||||
intercept := (sum[1] / f) - (gradient * sum[0] / f)
|
||||
|
||||
// Create the new regression series
|
||||
for j := 0; j < len(s); j++ {
|
||||
regressions = append(regressions, Coordinate{
|
||||
X: s[j].X,
|
||||
Y: s[j].X*gradient + intercept,
|
||||
})
|
||||
}
|
||||
|
||||
return regressions, nil
|
||||
}
|
||||
|
||||
// ExponentialRegression returns an exponential regression on data series
|
||||
func ExponentialRegression(s Series) (regressions Series, err error) {
|
||||
|
||||
if len(s) == 0 {
|
||||
return nil, EmptyInputErr
|
||||
}
|
||||
|
||||
var sum [6]float64
|
||||
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i].Y < 0 {
|
||||
return nil, YCoordErr
|
||||
}
|
||||
sum[0] += s[i].X
|
||||
sum[1] += s[i].Y
|
||||
sum[2] += s[i].X * s[i].X * s[i].Y
|
||||
sum[3] += s[i].Y * math.Log(s[i].Y)
|
||||
sum[4] += s[i].X * s[i].Y * math.Log(s[i].Y)
|
||||
sum[5] += s[i].X * s[i].Y
|
||||
}
|
||||
|
||||
denominator := (sum[1]*sum[2] - sum[5]*sum[5])
|
||||
a := math.Pow(math.E, (sum[2]*sum[3]-sum[5]*sum[4])/denominator)
|
||||
b := (sum[1]*sum[4] - sum[5]*sum[3]) / denominator
|
||||
|
||||
for j := 0; j < len(s); j++ {
|
||||
regressions = append(regressions, Coordinate{
|
||||
X: s[j].X,
|
||||
Y: a * math.Exp(b*s[j].X),
|
||||
})
|
||||
}
|
||||
|
||||
return regressions, nil
|
||||
}
|
||||
|
||||
// LogarithmicRegression returns an logarithmic regression on data series
|
||||
func LogarithmicRegression(s Series) (regressions Series, err error) {
|
||||
|
||||
if len(s) == 0 {
|
||||
return nil, EmptyInputErr
|
||||
}
|
||||
|
||||
var sum [4]float64
|
||||
|
||||
i := 0
|
||||
for ; i < len(s); i++ {
|
||||
sum[0] += math.Log(s[i].X)
|
||||
sum[1] += s[i].Y * math.Log(s[i].X)
|
||||
sum[2] += s[i].Y
|
||||
sum[3] += math.Pow(math.Log(s[i].X), 2)
|
||||
}
|
||||
|
||||
f := float64(i)
|
||||
a := (f*sum[1] - sum[2]*sum[0]) / (f*sum[3] - sum[0]*sum[0])
|
||||
b := (sum[2] - a*sum[0]) / f
|
||||
|
||||
for j := 0; j < len(s); j++ {
|
||||
regressions = append(regressions, Coordinate{
|
||||
X: s[j].X,
|
||||
Y: b + a*math.Log(s[j].X),
|
||||
})
|
||||
}
|
||||
|
||||
return regressions, nil
|
||||
}
|
||||
38
vendor/github.com/montanaflynn/stats/round.go
generated
vendored
Normal file
38
vendor/github.com/montanaflynn/stats/round.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package stats
|
||||
|
||||
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
|
||||
}
|
||||
76
vendor/github.com/montanaflynn/stats/sample.go
generated
vendored
Normal file
76
vendor/github.com/montanaflynn/stats/sample.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Sample returns sample from input with replacement or without
|
||||
func Sample(input Float64Data, takenum int, replacement bool) ([]float64, error) {
|
||||
|
||||
if input.Len() == 0 {
|
||||
return nil, EmptyInputErr
|
||||
}
|
||||
|
||||
length := input.Len()
|
||||
if replacement {
|
||||
|
||||
result := Float64Data{}
|
||||
rand.Seed(unixnano())
|
||||
|
||||
// In every step, randomly take the num for
|
||||
for i := 0; i < takenum; i++ {
|
||||
idx := rand.Intn(length)
|
||||
result = append(result, input[idx])
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
} else if !replacement && takenum <= length {
|
||||
|
||||
rand.Seed(unixnano())
|
||||
|
||||
// Get permutation of number of indexies
|
||||
perm := rand.Perm(length)
|
||||
result := Float64Data{}
|
||||
|
||||
// Get element of input by permutated index
|
||||
for _, idx := range perm[0:takenum] {
|
||||
result = append(result, input[idx])
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
return nil, BoundsErr
|
||||
}
|
||||
|
||||
// StableSample like stable sort, it returns samples from input while keeps the order of original data.
|
||||
func StableSample(input Float64Data, takenum int) ([]float64, error) {
|
||||
if input.Len() == 0 {
|
||||
return nil, EmptyInputErr
|
||||
}
|
||||
|
||||
length := input.Len()
|
||||
|
||||
if takenum <= length {
|
||||
|
||||
rand.Seed(unixnano())
|
||||
|
||||
perm := rand.Perm(length)
|
||||
perm = perm[0:takenum]
|
||||
// Sort perm before applying
|
||||
sort.Ints(perm)
|
||||
result := Float64Data{}
|
||||
|
||||
for _, idx := range perm {
|
||||
result = append(result, input[idx])
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
return nil, BoundsErr
|
||||
}
|
||||
18
vendor/github.com/montanaflynn/stats/sigmoid.go
generated
vendored
Normal file
18
vendor/github.com/montanaflynn/stats/sigmoid.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// Sigmoid returns the input values in the range of -1 to 1
|
||||
// along the sigmoid or s-shaped curve, commonly used in
|
||||
// machine learning while training neural networks as an
|
||||
// activation function.
|
||||
func Sigmoid(input Float64Data) ([]float64, error) {
|
||||
if input.Len() == 0 {
|
||||
return Float64Data{}, EmptyInput
|
||||
}
|
||||
s := make([]float64, len(input))
|
||||
for i, v := range input {
|
||||
s[i] = 1 / (1 + math.Exp(-v))
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
25
vendor/github.com/montanaflynn/stats/softmax.go
generated
vendored
Normal file
25
vendor/github.com/montanaflynn/stats/softmax.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// SoftMax returns the input values in the range of 0 to 1
|
||||
// with sum of all the probabilities being equal to one. It
|
||||
// is commonly used in machine learning neural networks.
|
||||
func SoftMax(input Float64Data) ([]float64, error) {
|
||||
if input.Len() == 0 {
|
||||
return Float64Data{}, EmptyInput
|
||||
}
|
||||
|
||||
s := 0.0
|
||||
c, _ := Max(input)
|
||||
for _, e := range input {
|
||||
s += math.Exp(e - c)
|
||||
}
|
||||
|
||||
sm := make([]float64, len(input))
|
||||
for i, v := range input {
|
||||
sm[i] = math.Exp(v-c) / s
|
||||
}
|
||||
|
||||
return sm, nil
|
||||
}
|
||||
18
vendor/github.com/montanaflynn/stats/sum.go
generated
vendored
Normal file
18
vendor/github.com/montanaflynn/stats/sum.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// Sum adds all the numbers of a slice together
|
||||
func Sum(input Float64Data) (sum float64, err error) {
|
||||
|
||||
if input.Len() == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
// Add em up
|
||||
for _, n := range input {
|
||||
sum += n
|
||||
}
|
||||
|
||||
return sum, nil
|
||||
}
|
||||
43
vendor/github.com/montanaflynn/stats/util.go
generated
vendored
Normal file
43
vendor/github.com/montanaflynn/stats/util.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"time"
|
||||
)
|
||||
|
||||
// float64ToInt rounds a float64 to an int
|
||||
func float64ToInt(input float64) (output int) {
|
||||
r, _ := Round(input, 0)
|
||||
return int(r)
|
||||
}
|
||||
|
||||
// unixnano returns nanoseconds from UTC epoch
|
||||
func unixnano() int64 {
|
||||
return time.Now().UTC().UnixNano()
|
||||
}
|
||||
|
||||
// copyslice copies a slice of float64s
|
||||
func copyslice(input Float64Data) Float64Data {
|
||||
s := make(Float64Data, input.Len())
|
||||
copy(s, input)
|
||||
return s
|
||||
}
|
||||
|
||||
// sortedCopy returns a sorted copy of float64s
|
||||
func sortedCopy(input Float64Data) (copy Float64Data) {
|
||||
copy = copyslice(input)
|
||||
sort.Float64s(copy)
|
||||
return
|
||||
}
|
||||
|
||||
// sortedCopyDif returns a sorted copy of float64s
|
||||
// only if the original data isn't sorted.
|
||||
// Only use this if returned slice won't be manipulated!
|
||||
func sortedCopyDif(input Float64Data) (copy Float64Data) {
|
||||
if sort.Float64sAreSorted(input) {
|
||||
return input
|
||||
}
|
||||
copy = copyslice(input)
|
||||
sort.Float64s(copy)
|
||||
return
|
||||
}
|
||||
105
vendor/github.com/montanaflynn/stats/variance.go
generated
vendored
Normal file
105
vendor/github.com/montanaflynn/stats/variance.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package stats
|
||||
|
||||
import "math"
|
||||
|
||||
// _variance finds the variance for both population and sample data
|
||||
func _variance(input Float64Data, sample int) (variance float64, err error) {
|
||||
|
||||
if input.Len() == 0 {
|
||||
return math.NaN(), EmptyInputErr
|
||||
}
|
||||
|
||||
// Sum the square of the mean subtracted from each number
|
||||
m, _ := Mean(input)
|
||||
|
||||
for _, n := range input {
|
||||
variance += (n - m) * (n - m)
|
||||
}
|
||||
|
||||
// When getting the mean of the squared differences
|
||||
// "sample" will allow us to know if it's a sample
|
||||
// or population and wether to subtract by one or not
|
||||
return variance / float64((input.Len() - (1 * sample))), nil
|
||||
}
|
||||
|
||||
// Variance the amount of variation in the dataset
|
||||
func Variance(input Float64Data) (sdev float64, err error) {
|
||||
return PopulationVariance(input)
|
||||
}
|
||||
|
||||
// PopulationVariance finds the amount of variance within a population
|
||||
func PopulationVariance(input Float64Data) (pvar float64, err error) {
|
||||
|
||||
v, err := _variance(input, 0)
|
||||
if err != nil {
|
||||
return math.NaN(), err
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// SampleVariance finds the amount of variance within a sample
|
||||
func SampleVariance(input Float64Data) (svar float64, err error) {
|
||||
|
||||
v, err := _variance(input, 1)
|
||||
if err != nil {
|
||||
return math.NaN(), err
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Covariance is a measure of how much two sets of data change
|
||||
func Covariance(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
|
||||
}
|
||||
|
||||
m1, _ := Mean(data1)
|
||||
m2, _ := Mean(data2)
|
||||
|
||||
// Calculate sum of squares
|
||||
var ss float64
|
||||
for i := 0; i < l1; i++ {
|
||||
delta1 := (data1.Get(i) - m1)
|
||||
delta2 := (data2.Get(i) - m2)
|
||||
ss += (delta1*delta2 - ss) / float64(i+1)
|
||||
}
|
||||
|
||||
return ss * float64(l1) / float64(l1-1), nil
|
||||
}
|
||||
|
||||
// CovariancePopulation computes covariance for entire population between two variables.
|
||||
func CovariancePopulation(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
|
||||
}
|
||||
|
||||
m1, _ := Mean(data1)
|
||||
m2, _ := Mean(data2)
|
||||
|
||||
var s float64
|
||||
for i := 0; i < l1; i++ {
|
||||
delta1 := (data1.Get(i) - m1)
|
||||
delta2 := (data2.Get(i) - m2)
|
||||
s += delta1 * delta2
|
||||
}
|
||||
|
||||
return s / float64(l1), nil
|
||||
}
|
||||
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@@ -1045,6 +1045,9 @@ github.com/moby/sys/userns
|
||||
## explicit; go 1.18
|
||||
github.com/moby/term
|
||||
github.com/moby/term/windows
|
||||
# github.com/montanaflynn/stats v0.7.1
|
||||
## explicit; go 1.13
|
||||
github.com/montanaflynn/stats
|
||||
# github.com/morikuni/aec v1.0.0
|
||||
## explicit
|
||||
github.com/morikuni/aec
|
||||
|
||||
Reference in New Issue
Block a user