sdtoolkit for Python
sdtoolkit for Python
Part of statistics-calculator-toolkit, which ships the same API for several languages.
sdtoolkit is a small, dependency-free Python package for standard
deviation, variance, sum of squares, relative standard deviation (RSD) and
coefficient of variation, with a command-line interface. It uses only the
standard library and supports Python 3.9 and later.
Problems it solves
- Picking the wrong formula. Population and sample versions have separate, explicitly named functions, and the CLI prints which divisor it used.
- Silent precision loss. The shortcut
Σx² − (Σx)²/ncan return zero or even a negative variance for data far from zero. sdtoolkit uses a two-pass algorithm withmath.fsum. - Garbage in, number out.
None,NaN, infinities, booleans and strings raise a clear error instead of producing a plausible-looking result. Missing values are never skipped silently. - Undefined RSD. A zero mean raises an error instead of returning infinity or dividing by zero.
Features
| function | returns |
|---|---|
mean(data) |
arithmetic mean |
sum_of_squares(data) |
SS = Σ(x − x̄)² |
population_variance(data) |
SS / N |
sample_variance(data) |
SS / (n − 1) |
population_stdev(data) |
√(SS / N) |
sample_stdev(data) |
√(SS / (n − 1)) |
relative_std_dev(data, population=False) |
100 × SD / |mean|, in percent |
coefficient_of_variation(data, population=False) |
SD / |mean|, as a ratio |
describe(data, population=False) |
Summary dataclass with all of the above plus min, max, range |
All errors are raised as sdtoolkit.StatisticsError, a subclass of
ValueError.
Install
pip install sdtoolkit
Or from a clone, without installing:
PYTHONPATH=src python -m sdtoolkit 1 2 3
Usage
Python
>>> import sdtoolkit as sd
>>> data = [2, 4, 4, 4, 5, 5, 7, 9]
>>> sd.mean(data)
5.0
>>> sd.sum_of_squares(data)
32.0
>>> sd.population_variance(data), sd.population_stdev(data)
(4.0, 2.0)
>>> sd.sample_variance(data), sd.sample_stdev(data)
(4.571428571428571, 2.138089935299395)
>>> sd.relative_std_dev(data)
42.7617987059879
>>> sd.coefficient_of_variation(data, population=True)
0.4
>>> sd.describe(data)
Summary(n=8, mean=5.0, minimum=2.0, maximum=9.0, range=7.0, sum_of_squares=32.0, variance=4.571428571428571, stdev=2.138089935299395, rsd_percent=42.7617987059879, population=False)
>>> sd.describe(data, population=True).as_dict()["stdev"]
2.0
Command line
$ python -m sdtoolkit 2 4 4 4 5 5 7 9
n 8
mean 5
min 2
max 9
range 7
sum of squares 32
sample variance 4.571428571
sample std dev 2.138089935
RSD (%) 42.76179871
(divisor: n - 1)
$ python -m sdtoolkit --population 2 4 4 4 5 5 7 9
n 8
mean 5
min 2
max 9
range 7
sum of squares 32
population variance 4
population std dev 2
RSD (%) 40
(divisor: N)
Read one column of a CSV file (lines starting with # are treated as
comments):
$ python -m sdtoolkit --csv examples/sample-datasets.csv --column lab_replicate_mg_l
n 10
mean 12.405
min 12.36
max 12.45
range 0.09
sum of squares 0.00825
sample variance 0.0009166666667
sample std dev 0.03027650354
RSD (%) 0.244066937
(divisor: n - 1)
Errors go to stderr with exit status 1:
$ python -m sdtoolkit 1 2 x
error: argument 3: 'x' is not a number
$ python -m sdtoolkit 5
error: sample statistics need at least 2 data points, got 1
After pip install . the same CLI is also available as sdtoolkit.
Population vs sample
Use the population functions when your data are the entire group you are describing. Use the sample functions when your data are drawn from a larger group you want to draw conclusions about. The sample formulas divide by n − 1 (Bessel’s correction), which makes the sample variance an unbiased estimate of the population variance, and they need at least two values.
describe, relative_std_dev, coefficient_of_variation and the CLI
default to the sample formulas. Details:
Sample vs population.
Formulas
x̄ = Σxᵢ / n
SS = Σ (xᵢ − x̄)²
σ² = SS / N σ = √σ²
s² = SS / (n − 1) s = √s²
CV = s / |x̄|
RSD = 100 × s / |x̄| %
A step-by-step walk-through of these formulas is on the standard deviation formula reference.
Further reading:
Example datasets
examples/sample-datasets.csv has three
small columns: lab replicate readings, exam scores and daily temperatures.
They are illustrative values made up for teaching, not real research
data. examples/worked-examples.md works
through each one by hand and checks the result with the code.
Accuracy and edge cases
- Algorithm. Two passes: the mean, then the squared deviations from it,
each summed with
math.fsum. A correction term removes the rounding error left in the mean. The test suite compares results with Python’sstatistics.pvariance,variance,pstdevandstdev(which use exact rational arithmetic) to a relative tolerance of 1e-12, including data offset by 10⁹ and 10¹². - Accepted input. Any iterable of
int,float,decimal.Decimalorfractions.Fraction. Decimals and fractions are converted tofloat, so their extra precision is not kept and results are alwaysfloat. - Rejected input.
bool,None, strings, NaN, ±infinity, complex numbers, and integers too large for a float raiseStatisticsErrornaming the offending item. - Missing values are not skipped.
Noneraises, and an empty CSV cell raises with its row number. Remove or impute missing data yourself so the choice is visible in your code. - Empty input raises. Sample statistics with one value raise. Population variance of one value is 0.
- Zero mean.
relative_std_devandcoefficient_of_variationraise;describesetsrsd_percenttoNone. RSD is only meaningful for ratio-scale data; see Relative standard deviation.
>>> sd.mean([1, None, 3])
Traceback (most recent call last):
...
sdtoolkit.core.StatisticsError: item 1: None (missing value); remove or fill it before computing
>>> sd.sample_stdev([1e9 + 4, 1e9 + 7, 1e9 + 13, 1e9 + 16]) ** 2
30.0
Tests
PYTHONPATH=src python -m unittest discover -s tests
The suite uses only unittest. GitHub Actions runs it on Python 3.9 to 3.13
(workflow).
Contributing
See CONTRIBUTING.md.
License
MIT. See LICENSE.