CLI tool
montanaflynn/stats avatar
montanaflynn/stats

montanaflynn/stats: A Dependency-Free Statistics Package for Go

A well tested and comprehensive Golang statistics library package with no dependencies.

3,025 stars176 forksGoMIT

At a glance

What is it?
A Go library that covers descriptive statistics, distances, distributions and moving windows without pulling in a single dependency. The API is wide, the error model is explicit, and the install is one go get.
Who is it for?
Adopt montanaflynn/stats when you need descriptive statistics, distances or normal-distribution helpers inside a Go service and you want to avoid a dependency tree. Skip it if you need regression, hypothesis testing or matrix linear algebra; the exported API does not list those.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What montanaflynn/stats solves for Go developers

Go's standard library has math and sort but no statistics package. If you need a median or a percentile inside a service, you either write the sort-and-index logic yourself or add a module that drags in more modules. This package takes the second path with the dependency count at zero: the repository's go.mod declares the module path github.com/montanaflynn/stats and a go directive of 1.13, and nothing else. The README describes it as "a well tested and comprehensive Golang statistics library / package / module with no dependencies."

The intended reader is a Go programmer who already has data in memory as numbers and wants summary values back. The package is not a data frame, not a plotting library and not a pipeline engine. It takes float64 slices and returns numbers or slices. That narrowness is the point: you can drop it into a CLI, an HTTP handler or a batch job and the only new thing in your module graph is this package.

The Float64Data type and the error contract

Everything funnels through one type. Float64Data is defined as []float64, and almost every exported function accepts it. Conversion from other shapes goes through LoadRawData, which takes an interface{} and returns Float64Data. The README shows three call patterns: a plain []float64 literal, stats.LoadRawData([]int{1, 2, 3, 4, 5}), and a mixed slice such as stats.LoadRawData([]interface{}{1.1, "2", 3}). That last example is the interesting one, because it means string digits are coerced rather than rejected.

The error model is a fixed set of sentinel values declared as package variables: ErrEmptyInput, ErrNaN, ErrNegative, ErrZero, ErrBounds, ErrSize, ErrInfValue and ErrYCoord. Each carries a plain message, for example ErrEmptyInput is "Input must not be empty." and ErrSize is "Must be the same length." Functions return these rather than panicking, so a service can decide whether an empty slice is a programming error or a legitimate no-data case. The trade-off is verbosity: nearly every call site needs an error check, and the two-value return shows up even for functions like ArgMax where the failure mode is narrow. The README does not document which of these sentinels each individual function returns, so you learn the mapping from the source or from pkg.go.dev.

Installing the package and computing a first median

Installation is a single module fetch. The README gives exactly one command, and it works from inside a module directory because the package is versioned with a v0 major version.

bash
go get github.com/montanaflynn/stats

After that, a minimal program imports the package, builds a slice, and calls Median. The README's own example uses six values and prints the result:

go
package main

import (
	"fmt"

	"github.com/montanaflynn/stats"
)

func main() {
	data := []float64{1.0, 2.1, 3.2, 4.823, 4.1, 5.8}
	median, _ := stats.Median(data)
	fmt.Println(median) // 3.65
}

The printed value is 3.65, which is the mean of the two middle values after sorting. The README then shows rounding the result with stats.Round(median, 0), which prints 4. Notice that both examples discard the error with the blank identifier. That is fine for a fixed literal, but in production you should branch on it, because Median on an empty slice returns ErrEmptyInput rather than zero.

If you prefer reading the API offline, the README documents two routes. The command-line route uses go doc, for instance go doc Median or go doc Float64Data. The browser route installs the pkgsite tool and serves it locally:

bash
go install golang.org/x/pkgsite/cmd/pkgsite@latest
pkgsite -http=:4444

That starts a server on port 4444, and the README points the browser at http://localhost:4444/github.com/montanaflynn/stats.

Where the API is broad: describe, distributions and windows

The exported surface is larger than a median-and-mean helper. Describe returns a *Description struct and takes the input, an allowNaN flag and a pointer to a percentile list, so one call can produce a summary block instead of a dozen calls. A variant, DescribePercentileFunc, accepts a percentileFunc so you can substitute your own percentile implementation, which matters because the package ships at least three: Percentile, PercentileNearestRank and PercentileWeighted.

The moving-window family covers MovingAverage, MovingMedian, MovingMin, MovingMax, MovingSum and MovingStdDev, each taking a window size. Cumulative variants exist too: CumulativeSum, CumulativeMax, CumulativeMin and CumulativeProduct. For time-series smoothing there is EWMA with an alpha parameter, and for change detection there is Diff and PercentChange.

The distribution coverage is concentrated on the normal case. Roughly two dozen Norm-prefixed functions cover the density, cumulative, survival, inverse-survival and quantile functions, plus NormSample, NormPpfRvs and NormBoxMullerRvs for random draws, NormFit for fitting location and scale, and NormStats for moments. There is also a separate geometric_distribution.go file in the repository root, so a geometric distribution is present even though the README excerpt does not enumerate its functions. Distance functions round out the set: EuclideanDistance, ManhattanDistance, ChebyshevDistance and MinkowskiDistance with a lambda parameter. Correlation work is covered by Pearson, KendallTau, Correlation, Covariance, CovariancePopulation and AutoCorrelation.

The boundary: no regression, no hypothesis tests

The omission that matters most is inferential statistics. Nothing in the exported API performs a t-test, an ANOVA, a chi-square test or a linear regression. If your task is deciding whether two samples differ, this package will hand you the means and standard deviations and stop there. You would compute the test statistic yourself or reach for a different library.

The second boundary is scale. Every function takes a slice and, where sorting is required, sorts it. There is no streaming accumulator, no sketch structure and no approximate quantile algorithm, so a percentile over a hundred million values means holding a hundred million float64 values in memory and sorting them. The package is built for in-process slices, not for a columnar store.

The third is numeric policy. The presence of ErrNaN, ErrInfValue and an allowNaN parameter on Describe means NaN handling is opt-in and call-site dependent. A slice containing NaN will behave differently depending on which function you call and which flag you pass. The README does not lay out a single consistent rule, so if your input can contain NaN you should test the specific functions you rely on rather than assuming uniform behaviour.

How it compares with gonum and with statsmodels

The closest Go alternative is gonum, whose stat package covers descriptive statistics, distributions, and also the linear algebra and optimisation machinery this library leaves out. The practical difference is the dependency graph. gonum is a set of modules with internal structure; montanaflynn/stats is one module with an empty require block. If you are writing a small service and your security or build policy makes every new module a review item, one module with no transitive dependencies is a different proposition from a numerical computing stack. If you need matrix decomposition, gonum is the answer and this package is not.

People also arrive here from Python. The search data shows queries about installing statsmodels, which is a different tool in a different language: statsmodels targets regression, time-series models and formal inference, and it sits on NumPy and pandas. Go has no equivalent single package, and montanaflynn/stats does not try to be one. The honest framing is that it replaces a handful of NumPy calls, not a modelling workflow.

Maintenance, releases and the MIT licence

The repository is not archived, and the last push was on 2026-09-09. Releases are frequent and versioned with a v0 major, with v0.12.6 tagged on 2026-09-09, v0.12.5 on 2026-08-28 and v0.12.4 on 2026-08-17. The CHANGELOG.md file and a .chglog directory are both present in the repository root, so release notes are generated rather than hand-written, and the Makefile has a release target that requires a TAG variable, runs a changelog script, commits, tags and pushes.

A v0 major means the maintainer reserves the right to make breaking changes without a major version bump, and the changelog is where you would look for them. The go.mod directive is 1.13, which is old enough that any current toolchain will build it, but it also means the package cannot use newer language features; that is a deliberate compatibility choice, not an oversight.

The licence is MIT, which is permissive and permits use in closed-source products provided the copyright notice and permission notice are retained. That is a summary of the licence text, not legal advice; if your organisation has a licence review process, run the LICENSE file through it.

Upgrade cost is low day to day because the dependency set cannot change: there is nothing to bump transitively. The real cost is behavioural. Because the API is a flat set of functions with sentinel errors, a change in how a percentile is computed or how NaN is treated would surface as a changed number rather than a compile error. Pin the version in go.mod and run the package's own test suite against your data if you upgrade.

Editorial conclusion

Adopt montanaflynn/stats when you need descriptive statistics, distances or normal-distribution helpers inside a Go service and you want to avoid a dependency tree. Skip it if you need regression, hypothesis testing or matrix linear algebra; the exported API does not list those. Before committing, check the go.mod directive against your toolchain, confirm which error each function returns for empty input, and read the pkg.go.dev page for the percentile and interpolation variants, since the README does not explain how Percentile, PercentileNearestRank and PercentileWeighted differ.

Frequently asked questions

How do I install montanaflynn/stats?

Run go get github.com/montanaflynn/stats from inside your module. The README gives that as the only installation step, and the module has no dependencies, so nothing else is pulled in.

What does montanaflynn/stats return for an empty input slice?

The package declares a sentinel error, ErrEmptyInput, whose message is "Input must not be empty." Functions that need data return it instead of panicking, so the caller has to check the error rather than assume a zero value.

Does montanaflynn/stats do linear regression or hypothesis testing?

No. The exported API listed in the README covers descriptive statistics, distances, correlations, moving windows and normal and geometric distributions, but it does not include regression or significance tests.

Official sources

  1. Issues
  2. License: MIT
  3. montanaflynn/stats on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/montanaflynn-stats.svg)](https://hysenlabs.com/projects/montanaflynn-stats)