sdtoolkit 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sdtoolkit-0.1.0/LICENSE +21 -0
- sdtoolkit-0.1.0/PKG-INFO +247 -0
- sdtoolkit-0.1.0/README.md +103 -0
- sdtoolkit-0.1.0/docs/python.md +227 -0
- sdtoolkit-0.1.0/pyproject.toml +32 -0
- sdtoolkit-0.1.0/setup.cfg +4 -0
- sdtoolkit-0.1.0/src/sdtoolkit/__init__.py +31 -0
- sdtoolkit-0.1.0/src/sdtoolkit/__main__.py +5 -0
- sdtoolkit-0.1.0/src/sdtoolkit/cli.py +93 -0
- sdtoolkit-0.1.0/src/sdtoolkit/core.py +199 -0
- sdtoolkit-0.1.0/src/sdtoolkit.egg-info/PKG-INFO +247 -0
- sdtoolkit-0.1.0/src/sdtoolkit.egg-info/SOURCES.txt +14 -0
- sdtoolkit-0.1.0/src/sdtoolkit.egg-info/dependency_links.txt +1 -0
- sdtoolkit-0.1.0/src/sdtoolkit.egg-info/entry_points.txt +2 -0
- sdtoolkit-0.1.0/src/sdtoolkit.egg-info/top_level.txt +1 -0
- sdtoolkit-0.1.0/tests/test_core.py +242 -0
sdtoolkit-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ramesh-xyz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
sdtoolkit-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sdtoolkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Dependency-free standard deviation, variance and relative standard deviation for Python
|
|
5
|
+
Author: Ramesh-xyz
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://standarddeviationcalculator.net/
|
|
8
|
+
Project-URL: Documentation, https://ramesh-xyz.github.io/statistics-calculator-toolkit/python.html
|
|
9
|
+
Project-URL: Source, https://github.com/Ramesh-xyz/statistics-calculator-toolkit
|
|
10
|
+
Project-URL: Issues, https://github.com/Ramesh-xyz/statistics-calculator-toolkit/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/CHANGELOG.md
|
|
12
|
+
Keywords: standard deviation,variance,coefficient of variation,statistics
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
|
|
21
|
+
# sdtoolkit for Python
|
|
22
|
+
|
|
23
|
+
Part of [statistics-calculator-toolkit](https://github.com/Ramesh-xyz/statistics-calculator-toolkit), which ships the same API for
|
|
24
|
+
[several languages](https://ramesh-xyz.github.io/statistics-calculator-toolkit/).
|
|
25
|
+
|
|
26
|
+
`sdtoolkit` is a small, dependency-free Python package for standard
|
|
27
|
+
deviation, variance, sum of squares, relative standard deviation (RSD) and
|
|
28
|
+
coefficient of variation, with a command-line interface. It uses only the
|
|
29
|
+
standard library and supports Python 3.9 and later.
|
|
30
|
+
|
|
31
|
+
## Problems it solves
|
|
32
|
+
|
|
33
|
+
- **Picking the wrong formula.** Population and sample versions have
|
|
34
|
+
separate, explicitly named functions, and the CLI prints which divisor it
|
|
35
|
+
used.
|
|
36
|
+
- **Silent precision loss.** The shortcut `Σx² − (Σx)²/n` can return zero or
|
|
37
|
+
even a negative variance for data far from zero. sdtoolkit uses a two-pass
|
|
38
|
+
algorithm with `math.fsum`.
|
|
39
|
+
- **Garbage in, number out.** `None`, `NaN`, infinities, booleans and strings
|
|
40
|
+
raise a clear error instead of producing a plausible-looking result. Missing
|
|
41
|
+
values are never skipped silently.
|
|
42
|
+
- **Undefined RSD.** A zero mean raises an error instead of returning
|
|
43
|
+
infinity or dividing by zero.
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
| function | returns |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `mean(data)` | arithmetic mean |
|
|
50
|
+
| `sum_of_squares(data)` | SS = Σ(x − x̄)² |
|
|
51
|
+
| `population_variance(data)` | SS / N |
|
|
52
|
+
| `sample_variance(data)` | SS / (n − 1) |
|
|
53
|
+
| `population_stdev(data)` | √(SS / N) |
|
|
54
|
+
| `sample_stdev(data)` | √(SS / (n − 1)) |
|
|
55
|
+
| `relative_std_dev(data, population=False)` | 100 × SD / \|mean\|, in percent |
|
|
56
|
+
| `coefficient_of_variation(data, population=False)` | SD / \|mean\|, as a ratio |
|
|
57
|
+
| `describe(data, population=False)` | `Summary` dataclass with all of the above plus min, max, range |
|
|
58
|
+
|
|
59
|
+
All errors are raised as `sdtoolkit.StatisticsError`, a subclass of
|
|
60
|
+
`ValueError`.
|
|
61
|
+
|
|
62
|
+
## Install
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
pip install sdtoolkit
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or from a clone, without installing:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
PYTHONPATH=src python -m sdtoolkit 1 2 3
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Usage
|
|
75
|
+
|
|
76
|
+
### Python
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
>>> import sdtoolkit as sd
|
|
80
|
+
>>> data = [2, 4, 4, 4, 5, 5, 7, 9]
|
|
81
|
+
>>> sd.mean(data)
|
|
82
|
+
5.0
|
|
83
|
+
>>> sd.sum_of_squares(data)
|
|
84
|
+
32.0
|
|
85
|
+
>>> sd.population_variance(data), sd.population_stdev(data)
|
|
86
|
+
(4.0, 2.0)
|
|
87
|
+
>>> sd.sample_variance(data), sd.sample_stdev(data)
|
|
88
|
+
(4.571428571428571, 2.138089935299395)
|
|
89
|
+
>>> sd.relative_std_dev(data)
|
|
90
|
+
42.7617987059879
|
|
91
|
+
>>> sd.coefficient_of_variation(data, population=True)
|
|
92
|
+
0.4
|
|
93
|
+
>>> sd.describe(data)
|
|
94
|
+
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)
|
|
95
|
+
>>> sd.describe(data, population=True).as_dict()["stdev"]
|
|
96
|
+
2.0
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Command line
|
|
100
|
+
|
|
101
|
+
```console
|
|
102
|
+
$ python -m sdtoolkit 2 4 4 4 5 5 7 9
|
|
103
|
+
n 8
|
|
104
|
+
mean 5
|
|
105
|
+
min 2
|
|
106
|
+
max 9
|
|
107
|
+
range 7
|
|
108
|
+
sum of squares 32
|
|
109
|
+
sample variance 4.571428571
|
|
110
|
+
sample std dev 2.138089935
|
|
111
|
+
RSD (%) 42.76179871
|
|
112
|
+
(divisor: n - 1)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```console
|
|
116
|
+
$ python -m sdtoolkit --population 2 4 4 4 5 5 7 9
|
|
117
|
+
n 8
|
|
118
|
+
mean 5
|
|
119
|
+
min 2
|
|
120
|
+
max 9
|
|
121
|
+
range 7
|
|
122
|
+
sum of squares 32
|
|
123
|
+
population variance 4
|
|
124
|
+
population std dev 2
|
|
125
|
+
RSD (%) 40
|
|
126
|
+
(divisor: N)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Read one column of a CSV file (lines starting with `#` are treated as
|
|
130
|
+
comments):
|
|
131
|
+
|
|
132
|
+
```console
|
|
133
|
+
$ python -m sdtoolkit --csv examples/sample-datasets.csv --column lab_replicate_mg_l
|
|
134
|
+
n 10
|
|
135
|
+
mean 12.405
|
|
136
|
+
min 12.36
|
|
137
|
+
max 12.45
|
|
138
|
+
range 0.09
|
|
139
|
+
sum of squares 0.00825
|
|
140
|
+
sample variance 0.0009166666667
|
|
141
|
+
sample std dev 0.03027650354
|
|
142
|
+
RSD (%) 0.244066937
|
|
143
|
+
(divisor: n - 1)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Errors go to stderr with exit status 1:
|
|
147
|
+
|
|
148
|
+
```console
|
|
149
|
+
$ python -m sdtoolkit 1 2 x
|
|
150
|
+
error: argument 3: 'x' is not a number
|
|
151
|
+
$ python -m sdtoolkit 5
|
|
152
|
+
error: sample statistics need at least 2 data points, got 1
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
After `pip install .` the same CLI is also available as `sdtoolkit`.
|
|
156
|
+
|
|
157
|
+
## Population vs sample
|
|
158
|
+
|
|
159
|
+
Use the population functions when your data are the entire group you are
|
|
160
|
+
describing. Use the sample functions when your data are drawn from a larger
|
|
161
|
+
group you want to draw conclusions about. The sample formulas divide by
|
|
162
|
+
n − 1 (Bessel's correction), which makes the sample variance an unbiased
|
|
163
|
+
estimate of the population variance, and they need at least two values.
|
|
164
|
+
|
|
165
|
+
`describe`, `relative_std_dev`, `coefficient_of_variation` and the CLI
|
|
166
|
+
default to the sample formulas. Details:
|
|
167
|
+
[Sample vs population](https://ramesh-xyz.github.io/statistics-calculator-toolkit/sample-vs-population.html).
|
|
168
|
+
|
|
169
|
+
## Formulas
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
x̄ = Σxᵢ / n
|
|
173
|
+
SS = Σ (xᵢ − x̄)²
|
|
174
|
+
σ² = SS / N σ = √σ²
|
|
175
|
+
s² = SS / (n − 1) s = √s²
|
|
176
|
+
CV = s / |x̄|
|
|
177
|
+
RSD = 100 × s / |x̄| %
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
A step-by-step walk-through of these formulas is on the
|
|
181
|
+
[standard deviation formula reference](https://standarddeviationcalculator.net/standard-deviation-formula/).
|
|
182
|
+
|
|
183
|
+
Further reading:
|
|
184
|
+
|
|
185
|
+
- [Standard deviation](https://ramesh-xyz.github.io/statistics-calculator-toolkit/standard-deviation.html)
|
|
186
|
+
- [Variance](https://ramesh-xyz.github.io/statistics-calculator-toolkit/variance.html)
|
|
187
|
+
- [Sample vs population](https://ramesh-xyz.github.io/statistics-calculator-toolkit/sample-vs-population.html)
|
|
188
|
+
- [Relative standard deviation](https://ramesh-xyz.github.io/statistics-calculator-toolkit/relative-standard-deviation.html)
|
|
189
|
+
- [Outliers](https://ramesh-xyz.github.io/statistics-calculator-toolkit/outliers.html)
|
|
190
|
+
|
|
191
|
+
## Example datasets
|
|
192
|
+
|
|
193
|
+
[`examples/sample-datasets.csv`](https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/examples/sample-datasets.csv) has three
|
|
194
|
+
small columns: lab replicate readings, exam scores and daily temperatures.
|
|
195
|
+
They are **illustrative values made up for teaching, not real research
|
|
196
|
+
data.** [`examples/worked-examples.md`](https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/examples/worked-examples.md) works
|
|
197
|
+
through each one by hand and checks the result with the code.
|
|
198
|
+
|
|
199
|
+
## Accuracy and edge cases
|
|
200
|
+
|
|
201
|
+
- **Algorithm.** Two passes: the mean, then the squared deviations from it,
|
|
202
|
+
each summed with `math.fsum`. A correction term removes the rounding error
|
|
203
|
+
left in the mean. The test suite compares results with Python's
|
|
204
|
+
`statistics.pvariance`, `variance`, `pstdev` and `stdev` (which use exact
|
|
205
|
+
rational arithmetic) to a relative tolerance of 1e-12, including data
|
|
206
|
+
offset by 10⁹ and 10¹².
|
|
207
|
+
- **Accepted input.** Any iterable of `int`, `float`, `decimal.Decimal` or
|
|
208
|
+
`fractions.Fraction`. Decimals and fractions are converted to `float`, so
|
|
209
|
+
their extra precision is not kept and results are always `float`.
|
|
210
|
+
- **Rejected input.** `bool`, `None`, strings, NaN, ±infinity, complex
|
|
211
|
+
numbers, and integers too large for a float raise `StatisticsError` naming
|
|
212
|
+
the offending item.
|
|
213
|
+
- **Missing values are not skipped.** `None` raises, and an empty CSV cell
|
|
214
|
+
raises with its row number. Remove or impute missing data yourself so the
|
|
215
|
+
choice is visible in your code.
|
|
216
|
+
- **Empty input** raises. **Sample statistics with one value** raise.
|
|
217
|
+
Population variance of one value is 0.
|
|
218
|
+
- **Zero mean.** `relative_std_dev` and `coefficient_of_variation` raise;
|
|
219
|
+
`describe` sets `rsd_percent` to `None`. RSD is only meaningful for
|
|
220
|
+
ratio-scale data; see
|
|
221
|
+
[Relative standard deviation](https://ramesh-xyz.github.io/statistics-calculator-toolkit/relative-standard-deviation.html).
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
>>> sd.mean([1, None, 3])
|
|
225
|
+
Traceback (most recent call last):
|
|
226
|
+
...
|
|
227
|
+
sdtoolkit.core.StatisticsError: item 1: None (missing value); remove or fill it before computing
|
|
228
|
+
>>> sd.sample_stdev([1e9 + 4, 1e9 + 7, 1e9 + 13, 1e9 + 16]) ** 2
|
|
229
|
+
30.0
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Tests
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
PYTHONPATH=src python -m unittest discover -s tests
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
The suite uses only `unittest`. GitHub Actions runs it on Python 3.9 to 3.13
|
|
239
|
+
([workflow](https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/.github/workflows/test-python.yml)).
|
|
240
|
+
|
|
241
|
+
## Contributing
|
|
242
|
+
|
|
243
|
+
See [CONTRIBUTING.md](https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/CONTRIBUTING.md).
|
|
244
|
+
|
|
245
|
+
## License
|
|
246
|
+
|
|
247
|
+
MIT. See [LICENSE](https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/LICENSE).
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# statistics-calculator-toolkit
|
|
2
|
+
|
|
3
|
+
Small, dependency-free libraries for the mean, sum of squared deviations,
|
|
4
|
+
population and sample variance, population and sample standard deviation,
|
|
5
|
+
coefficient of variation and relative standard deviation (RSD). Ten
|
|
6
|
+
languages share one API, one algorithm and one set of test vectors.
|
|
7
|
+
|
|
8
|
+
Documentation: <https://ramesh-xyz.github.io/statistics-calculator-toolkit/>
|
|
9
|
+
|
|
10
|
+
## Problems it solves
|
|
11
|
+
|
|
12
|
+
- **Picking the wrong formula.** Population and sample versions are separate,
|
|
13
|
+
explicitly named functions.
|
|
14
|
+
- **Silent precision loss.** The shortcut `Σx² − (Σx)²/n` can return zero or
|
|
15
|
+
a negative variance for data far from zero. Every implementation here uses
|
|
16
|
+
a corrected two-pass algorithm with compensated summation.
|
|
17
|
+
- **Garbage in, number out.** NaN, infinities and (in dynamic languages)
|
|
18
|
+
`null`, booleans and strings raise an error naming the bad item. Missing
|
|
19
|
+
values are never skipped silently.
|
|
20
|
+
- **Undefined RSD.** A zero mean raises an error instead of returning
|
|
21
|
+
infinity.
|
|
22
|
+
|
|
23
|
+
## Packages
|
|
24
|
+
|
|
25
|
+
| language | directory | registry | install |
|
|
26
|
+
|---|---|---|---|
|
|
27
|
+
| Python | [`src/sdtoolkit`](src/sdtoolkit) | PyPI | `pip install sdtoolkit` |
|
|
28
|
+
| JavaScript / TypeScript | [`js`](js) | npm | `npm install @rameshxyz/sdtoolkit` |
|
|
29
|
+
| Rust | [`rust`](rust) | crates.io | `cargo add sdtoolkit` |
|
|
30
|
+
| Go | [`go/sdtoolkit`](go/sdtoolkit) | Go modules | `go get github.com/Ramesh-xyz/statistics-calculator-toolkit/go/sdtoolkit` |
|
|
31
|
+
| R | [`r`](r) | CRAN | `install.packages("sdcalc")` |
|
|
32
|
+
| Java / Kotlin | [`java`](java) | Maven Central | `io.github.ramesh-xyz:sdtoolkit` |
|
|
33
|
+
| C# / .NET | [`dotnet`](dotnet) | NuGet | `dotnet add package SdToolkit` |
|
|
34
|
+
| Ruby | [`ruby`](ruby) | RubyGems | `gem install sdtoolkit` |
|
|
35
|
+
| PHP | [`php`](php) | Packagist | `composer require ramesh-xyz/sdtoolkit` |
|
|
36
|
+
| Dart / Flutter | [`dart`](dart) | pub.dev | `dart pub add sdtoolkit` |
|
|
37
|
+
|
|
38
|
+
Each package is released on its own from a git tag (see
|
|
39
|
+
[RELEASING.md](RELEASING.md)); [CHANGELOG.md](CHANGELOG.md) lists what has
|
|
40
|
+
shipped. Each directory's README has usage examples for that language. The
|
|
41
|
+
Python package and its command-line tool are documented in
|
|
42
|
+
[docs/python.md](docs/python.md).
|
|
43
|
+
|
|
44
|
+
## Example
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
>>> import sdtoolkit as sd
|
|
48
|
+
>>> data = [2, 4, 4, 4, 5, 5, 7, 9]
|
|
49
|
+
>>> sd.population_variance(data), sd.population_stdev(data)
|
|
50
|
+
(4.0, 2.0)
|
|
51
|
+
>>> sd.sample_variance(data), sd.sample_stdev(data)
|
|
52
|
+
(4.571428571428571, 2.138089935299395)
|
|
53
|
+
>>> sd.relative_std_dev(data)
|
|
54
|
+
42.7617987059879
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```console
|
|
58
|
+
$ python -m sdtoolkit --population 2 4 4 4 5 5 7 9
|
|
59
|
+
n 8
|
|
60
|
+
mean 5
|
|
61
|
+
min 2
|
|
62
|
+
max 9
|
|
63
|
+
range 7
|
|
64
|
+
sum of squares 32
|
|
65
|
+
population variance 4
|
|
66
|
+
population std dev 2
|
|
67
|
+
RSD (%) 40
|
|
68
|
+
(divisor: N)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
The same numbers come out of every language; [docs/api.md](docs/api.md)
|
|
72
|
+
lists the function names per language, the shared edge-case behaviour and the
|
|
73
|
+
floating-point differences.
|
|
74
|
+
|
|
75
|
+
## Formulas
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
x̄ = Σxᵢ / n
|
|
79
|
+
SS = Σ (xᵢ − x̄)²
|
|
80
|
+
σ² = SS / N σ = √σ²
|
|
81
|
+
s² = SS / (n − 1) s = √s²
|
|
82
|
+
CV = s / |x̄|
|
|
83
|
+
RSD = 100 × s / |x̄| %
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Guides: [standard deviation](docs/standard-deviation.md),
|
|
87
|
+
[variance](docs/variance.md),
|
|
88
|
+
[sample vs population](docs/sample-vs-population.md),
|
|
89
|
+
[relative standard deviation](docs/relative-standard-deviation.md),
|
|
90
|
+
[outliers](docs/outliers.md). Illustrative datasets and hand-worked examples
|
|
91
|
+
are in [examples/](examples).
|
|
92
|
+
|
|
93
|
+
## Interactive Standard Deviation Calculator
|
|
94
|
+
|
|
95
|
+
For an interactive online calculator and additional worked examples, visit [StandardDeviationCalculator.net](https://standarddeviationcalculator.net/).
|
|
96
|
+
|
|
97
|
+
## Contributing
|
|
98
|
+
|
|
99
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# sdtoolkit for Python
|
|
2
|
+
|
|
3
|
+
Part of [statistics-calculator-toolkit](https://github.com/Ramesh-xyz/statistics-calculator-toolkit), which ships the same API for
|
|
4
|
+
[several languages](https://ramesh-xyz.github.io/statistics-calculator-toolkit/).
|
|
5
|
+
|
|
6
|
+
`sdtoolkit` is a small, dependency-free Python package for standard
|
|
7
|
+
deviation, variance, sum of squares, relative standard deviation (RSD) and
|
|
8
|
+
coefficient of variation, with a command-line interface. It uses only the
|
|
9
|
+
standard library and supports Python 3.9 and later.
|
|
10
|
+
|
|
11
|
+
## Problems it solves
|
|
12
|
+
|
|
13
|
+
- **Picking the wrong formula.** Population and sample versions have
|
|
14
|
+
separate, explicitly named functions, and the CLI prints which divisor it
|
|
15
|
+
used.
|
|
16
|
+
- **Silent precision loss.** The shortcut `Σx² − (Σx)²/n` can return zero or
|
|
17
|
+
even a negative variance for data far from zero. sdtoolkit uses a two-pass
|
|
18
|
+
algorithm with `math.fsum`.
|
|
19
|
+
- **Garbage in, number out.** `None`, `NaN`, infinities, booleans and strings
|
|
20
|
+
raise a clear error instead of producing a plausible-looking result. Missing
|
|
21
|
+
values are never skipped silently.
|
|
22
|
+
- **Undefined RSD.** A zero mean raises an error instead of returning
|
|
23
|
+
infinity or dividing by zero.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
| function | returns |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `mean(data)` | arithmetic mean |
|
|
30
|
+
| `sum_of_squares(data)` | SS = Σ(x − x̄)² |
|
|
31
|
+
| `population_variance(data)` | SS / N |
|
|
32
|
+
| `sample_variance(data)` | SS / (n − 1) |
|
|
33
|
+
| `population_stdev(data)` | √(SS / N) |
|
|
34
|
+
| `sample_stdev(data)` | √(SS / (n − 1)) |
|
|
35
|
+
| `relative_std_dev(data, population=False)` | 100 × SD / \|mean\|, in percent |
|
|
36
|
+
| `coefficient_of_variation(data, population=False)` | SD / \|mean\|, as a ratio |
|
|
37
|
+
| `describe(data, population=False)` | `Summary` dataclass with all of the above plus min, max, range |
|
|
38
|
+
|
|
39
|
+
All errors are raised as `sdtoolkit.StatisticsError`, a subclass of
|
|
40
|
+
`ValueError`.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
pip install sdtoolkit
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or from a clone, without installing:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
PYTHONPATH=src python -m sdtoolkit 1 2 3
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Usage
|
|
55
|
+
|
|
56
|
+
### Python
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
>>> import sdtoolkit as sd
|
|
60
|
+
>>> data = [2, 4, 4, 4, 5, 5, 7, 9]
|
|
61
|
+
>>> sd.mean(data)
|
|
62
|
+
5.0
|
|
63
|
+
>>> sd.sum_of_squares(data)
|
|
64
|
+
32.0
|
|
65
|
+
>>> sd.population_variance(data), sd.population_stdev(data)
|
|
66
|
+
(4.0, 2.0)
|
|
67
|
+
>>> sd.sample_variance(data), sd.sample_stdev(data)
|
|
68
|
+
(4.571428571428571, 2.138089935299395)
|
|
69
|
+
>>> sd.relative_std_dev(data)
|
|
70
|
+
42.7617987059879
|
|
71
|
+
>>> sd.coefficient_of_variation(data, population=True)
|
|
72
|
+
0.4
|
|
73
|
+
>>> sd.describe(data)
|
|
74
|
+
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)
|
|
75
|
+
>>> sd.describe(data, population=True).as_dict()["stdev"]
|
|
76
|
+
2.0
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Command line
|
|
80
|
+
|
|
81
|
+
```console
|
|
82
|
+
$ python -m sdtoolkit 2 4 4 4 5 5 7 9
|
|
83
|
+
n 8
|
|
84
|
+
mean 5
|
|
85
|
+
min 2
|
|
86
|
+
max 9
|
|
87
|
+
range 7
|
|
88
|
+
sum of squares 32
|
|
89
|
+
sample variance 4.571428571
|
|
90
|
+
sample std dev 2.138089935
|
|
91
|
+
RSD (%) 42.76179871
|
|
92
|
+
(divisor: n - 1)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```console
|
|
96
|
+
$ python -m sdtoolkit --population 2 4 4 4 5 5 7 9
|
|
97
|
+
n 8
|
|
98
|
+
mean 5
|
|
99
|
+
min 2
|
|
100
|
+
max 9
|
|
101
|
+
range 7
|
|
102
|
+
sum of squares 32
|
|
103
|
+
population variance 4
|
|
104
|
+
population std dev 2
|
|
105
|
+
RSD (%) 40
|
|
106
|
+
(divisor: N)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Read one column of a CSV file (lines starting with `#` are treated as
|
|
110
|
+
comments):
|
|
111
|
+
|
|
112
|
+
```console
|
|
113
|
+
$ python -m sdtoolkit --csv examples/sample-datasets.csv --column lab_replicate_mg_l
|
|
114
|
+
n 10
|
|
115
|
+
mean 12.405
|
|
116
|
+
min 12.36
|
|
117
|
+
max 12.45
|
|
118
|
+
range 0.09
|
|
119
|
+
sum of squares 0.00825
|
|
120
|
+
sample variance 0.0009166666667
|
|
121
|
+
sample std dev 0.03027650354
|
|
122
|
+
RSD (%) 0.244066937
|
|
123
|
+
(divisor: n - 1)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Errors go to stderr with exit status 1:
|
|
127
|
+
|
|
128
|
+
```console
|
|
129
|
+
$ python -m sdtoolkit 1 2 x
|
|
130
|
+
error: argument 3: 'x' is not a number
|
|
131
|
+
$ python -m sdtoolkit 5
|
|
132
|
+
error: sample statistics need at least 2 data points, got 1
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
After `pip install .` the same CLI is also available as `sdtoolkit`.
|
|
136
|
+
|
|
137
|
+
## Population vs sample
|
|
138
|
+
|
|
139
|
+
Use the population functions when your data are the entire group you are
|
|
140
|
+
describing. Use the sample functions when your data are drawn from a larger
|
|
141
|
+
group you want to draw conclusions about. The sample formulas divide by
|
|
142
|
+
n − 1 (Bessel's correction), which makes the sample variance an unbiased
|
|
143
|
+
estimate of the population variance, and they need at least two values.
|
|
144
|
+
|
|
145
|
+
`describe`, `relative_std_dev`, `coefficient_of_variation` and the CLI
|
|
146
|
+
default to the sample formulas. Details:
|
|
147
|
+
[Sample vs population](https://ramesh-xyz.github.io/statistics-calculator-toolkit/sample-vs-population.html).
|
|
148
|
+
|
|
149
|
+
## Formulas
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
x̄ = Σxᵢ / n
|
|
153
|
+
SS = Σ (xᵢ − x̄)²
|
|
154
|
+
σ² = SS / N σ = √σ²
|
|
155
|
+
s² = SS / (n − 1) s = √s²
|
|
156
|
+
CV = s / |x̄|
|
|
157
|
+
RSD = 100 × s / |x̄| %
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
A step-by-step walk-through of these formulas is on the
|
|
161
|
+
[standard deviation formula reference](https://standarddeviationcalculator.net/standard-deviation-formula/).
|
|
162
|
+
|
|
163
|
+
Further reading:
|
|
164
|
+
|
|
165
|
+
- [Standard deviation](https://ramesh-xyz.github.io/statistics-calculator-toolkit/standard-deviation.html)
|
|
166
|
+
- [Variance](https://ramesh-xyz.github.io/statistics-calculator-toolkit/variance.html)
|
|
167
|
+
- [Sample vs population](https://ramesh-xyz.github.io/statistics-calculator-toolkit/sample-vs-population.html)
|
|
168
|
+
- [Relative standard deviation](https://ramesh-xyz.github.io/statistics-calculator-toolkit/relative-standard-deviation.html)
|
|
169
|
+
- [Outliers](https://ramesh-xyz.github.io/statistics-calculator-toolkit/outliers.html)
|
|
170
|
+
|
|
171
|
+
## Example datasets
|
|
172
|
+
|
|
173
|
+
[`examples/sample-datasets.csv`](https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/examples/sample-datasets.csv) has three
|
|
174
|
+
small columns: lab replicate readings, exam scores and daily temperatures.
|
|
175
|
+
They are **illustrative values made up for teaching, not real research
|
|
176
|
+
data.** [`examples/worked-examples.md`](https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/examples/worked-examples.md) works
|
|
177
|
+
through each one by hand and checks the result with the code.
|
|
178
|
+
|
|
179
|
+
## Accuracy and edge cases
|
|
180
|
+
|
|
181
|
+
- **Algorithm.** Two passes: the mean, then the squared deviations from it,
|
|
182
|
+
each summed with `math.fsum`. A correction term removes the rounding error
|
|
183
|
+
left in the mean. The test suite compares results with Python's
|
|
184
|
+
`statistics.pvariance`, `variance`, `pstdev` and `stdev` (which use exact
|
|
185
|
+
rational arithmetic) to a relative tolerance of 1e-12, including data
|
|
186
|
+
offset by 10⁹ and 10¹².
|
|
187
|
+
- **Accepted input.** Any iterable of `int`, `float`, `decimal.Decimal` or
|
|
188
|
+
`fractions.Fraction`. Decimals and fractions are converted to `float`, so
|
|
189
|
+
their extra precision is not kept and results are always `float`.
|
|
190
|
+
- **Rejected input.** `bool`, `None`, strings, NaN, ±infinity, complex
|
|
191
|
+
numbers, and integers too large for a float raise `StatisticsError` naming
|
|
192
|
+
the offending item.
|
|
193
|
+
- **Missing values are not skipped.** `None` raises, and an empty CSV cell
|
|
194
|
+
raises with its row number. Remove or impute missing data yourself so the
|
|
195
|
+
choice is visible in your code.
|
|
196
|
+
- **Empty input** raises. **Sample statistics with one value** raise.
|
|
197
|
+
Population variance of one value is 0.
|
|
198
|
+
- **Zero mean.** `relative_std_dev` and `coefficient_of_variation` raise;
|
|
199
|
+
`describe` sets `rsd_percent` to `None`. RSD is only meaningful for
|
|
200
|
+
ratio-scale data; see
|
|
201
|
+
[Relative standard deviation](https://ramesh-xyz.github.io/statistics-calculator-toolkit/relative-standard-deviation.html).
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
>>> sd.mean([1, None, 3])
|
|
205
|
+
Traceback (most recent call last):
|
|
206
|
+
...
|
|
207
|
+
sdtoolkit.core.StatisticsError: item 1: None (missing value); remove or fill it before computing
|
|
208
|
+
>>> sd.sample_stdev([1e9 + 4, 1e9 + 7, 1e9 + 13, 1e9 + 16]) ** 2
|
|
209
|
+
30.0
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Tests
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
PYTHONPATH=src python -m unittest discover -s tests
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
The suite uses only `unittest`. GitHub Actions runs it on Python 3.9 to 3.13
|
|
219
|
+
([workflow](https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/.github/workflows/test-python.yml)).
|
|
220
|
+
|
|
221
|
+
## Contributing
|
|
222
|
+
|
|
223
|
+
See [CONTRIBUTING.md](https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/CONTRIBUTING.md).
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
MIT. See [LICENSE](https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/LICENSE).
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sdtoolkit"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Dependency-free standard deviation, variance and relative standard deviation for Python"
|
|
9
|
+
readme = "docs/python.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [{ name = "Ramesh-xyz" }]
|
|
14
|
+
keywords = ["standard deviation", "variance", "coefficient of variation", "statistics"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://standarddeviationcalculator.net/"
|
|
23
|
+
Documentation = "https://ramesh-xyz.github.io/statistics-calculator-toolkit/python.html"
|
|
24
|
+
Source = "https://github.com/Ramesh-xyz/statistics-calculator-toolkit"
|
|
25
|
+
Issues = "https://github.com/Ramesh-xyz/statistics-calculator-toolkit/issues"
|
|
26
|
+
Changelog = "https://github.com/Ramesh-xyz/statistics-calculator-toolkit/blob/main/CHANGELOG.md"
|
|
27
|
+
|
|
28
|
+
[project.scripts]
|
|
29
|
+
sdtoolkit = "sdtoolkit.cli:main"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
where = ["src"]
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""sdtoolkit: dependency-free standard deviation, variance and RSD."""
|
|
2
|
+
|
|
3
|
+
from .core import (
|
|
4
|
+
StatisticsError,
|
|
5
|
+
Summary,
|
|
6
|
+
coefficient_of_variation,
|
|
7
|
+
describe,
|
|
8
|
+
mean,
|
|
9
|
+
population_stdev,
|
|
10
|
+
population_variance,
|
|
11
|
+
relative_std_dev,
|
|
12
|
+
sample_stdev,
|
|
13
|
+
sample_variance,
|
|
14
|
+
sum_of_squares,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__version__ = "0.1.0"
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"StatisticsError",
|
|
21
|
+
"Summary",
|
|
22
|
+
"coefficient_of_variation",
|
|
23
|
+
"describe",
|
|
24
|
+
"mean",
|
|
25
|
+
"population_stdev",
|
|
26
|
+
"population_variance",
|
|
27
|
+
"relative_std_dev",
|
|
28
|
+
"sample_stdev",
|
|
29
|
+
"sample_variance",
|
|
30
|
+
"sum_of_squares",
|
|
31
|
+
]
|