@zukhruf/statistics 0.8.7 → 0.8.9

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.
package/NOTICE CHANGED
@@ -3,7 +3,7 @@ Copyright 2026 ezzabuzaid
3
3
 
4
4
  This package ports the semantics of the methods lower, higher, linear and
5
5
  inverted_cdf of numpy.quantile in NumPy 2.5.4, including the _lerp of its
6
- linear method, and of numpy.sum and numpy.mean, Copyright (c) NumPy Developers, BSD 3-Clause License,
6
+ linear method, and of numpy.sum, numpy.mean and numpy.nanmean, Copyright (c) NumPy Developers, BSD 3-Clause License,
7
7
  https://github.com/numpy/numpy. The package does not include NumPy's code.
8
8
  The names of the percentile bootstrap follow SciPy (scipy.stats.bootstrap)
9
9
  and arch (arch.bootstrap.IIDBootstrap); the package includes no code of
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @zukhruf/statistics
2
2
 
3
- The percentile bootstrap, the quantile methods of NumPy and `numpy.sum` and `numpy.mean` in JavaScript, to the last bit. Use it when a TypeScript eval must give the same interval as a Python program, such as the summary of a benchmark or the comparison of two models.
3
+ The percentile bootstrap, the quantile methods of NumPy, and `numpy.sum`, `numpy.mean` and `numpy.nanmean` in JavaScript, to the last bit. Use it when a TypeScript eval must give the same interval as a Python program, such as the summary of a benchmark or the comparison of two models.
4
4
 
5
5
  The package is public on npm. Until 2026-11-07 it was private and reached through a workspace path (ADR 0001); it became public with `@zukhruf/evals`, which depends on it (backlog #3888).
6
6
 
@@ -14,6 +14,7 @@ import {
14
14
  Linear,
15
15
  PercentileInterval,
16
16
  mean,
17
+ nanmean,
17
18
  sum,
18
19
  } from '@zukhruf/statistics';
19
20
 
@@ -34,22 +35,24 @@ interval.isAbove(0); // true when the whole interval lies above 0
34
35
  new Linear().of([1, 2, 3, 4], 0.5); // 2.5, as numpy.quantile(a, 0.5)
35
36
  sum([0.1, 0.2, 0.3]); // 0.6000000000000001, as numpy.sum(a)
36
37
  mean([1, 2, 3, 4]); // 2.5, as numpy.mean(a)
38
+ nanmean([1, NaN, 3]); // 2, as numpy.nanmean(a)
37
39
  ```
38
40
 
39
- | Export | NumPy, SciPy or arch | What it does |
40
- | ----------------------------------------------- | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
41
- | `sum` | `numpy.sum` of a 1-D float64 array | The pairwise sum of NumPy: blocks of up to 128 values in 8 accumulators, and two halves for more values. It starts from 0, so values of −0 give 0. No values give 0. |
42
- | `mean` | `numpy.mean` of a 1-D float64 array | `sum` divided by the number of values. No values give NaN. |
43
- | `QuantileMethod` | the `method` of `numpy.quantile` | A rule that gives the value at the quantile `q` of sorted values: `of(sorted, q)`. `q` is from 0 to 1. A `q` out of that range, or no values, throws a `RangeError`. |
44
- | `Lower` | `method='lower'` | The value at the index `floor((n − 1)q)`. |
45
- | `Higher` | `method='higher'` | The value at the index `ceil((n − 1)q)`. |
46
- | `Linear` | `method='linear'`, the default of NumPy | The line between the two values around the index `(n − 1)q`, computed as NumPy's `_lerp` computes it, so the bits are NumPy's. d3-array's `quantileSorted` gives other bits for 1 value of 10. |
47
- | `InvertedCdf` | `method='inverted_cdf'` | The nearest rank: the value at the index `ceil(nq) − 1`, and the first value when `q` is 0. |
48
- | `ConfidenceInterval` | the `ConfidenceInterval` of `scipy.stats.bootstrap` | `low` and `high`. `isAbove(value)` is true when `low > value`, and `isBelow(value)` is true when `high < value`: the whole interval lies on one side of the value. |
49
- | `DifferenceInterval` (design for review, #3870) | the `ConfidenceInterval` of `scipy.stats.bootstrap`, with the observed statistic | A `ConfidenceInterval` of (change − baseline) with `observed`: the difference that the data gives. It is data only: it has no verdict. mteb's `ChangeVerdict`, the `Interval` of relevance-filtering and the `Interval` of event-detection hold the same three values. `@zukhruf/evals` gives it in each verdict of two runs. |
50
- | `ConfidenceIntervalMethod` | the `method` of `scipy.stats.bootstrap` | A rule that gives the confidence interval of a bootstrap distribution: `of(distribution)`. `PercentileInterval` is one. A caller with a rule of its own writes another. |
51
- | `PercentileInterval` | `method='percentile'` of `scipy.stats.bootstrap` | The `low` and the `high` quantile of a bootstrap distribution, both read with one quantile method, as `numpy.percentile` reads them. It sorts a copy, so the distribution does not change. |
52
- | `IidBootstrap` | `arch.bootstrap.IIDBootstrap`; `n_resamples` and `bootstrap_distribution` of SciPy | Draws `nResamples` resamples of the data, with replacement. `distribution(data, statistic)` gives the statistic of each resample. `interval(data, statistic, method)` gives the interval that a `ConfidenceIntervalMethod` reads from that distribution. Data with no items throws a `RangeError`. |
41
+ | Export | NumPy, SciPy or arch | What it does |
42
+ | -------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
43
+ | `sum` | `numpy.sum` of a 1-D float64 array | The pairwise sum of NumPy: blocks of up to 128 values in 8 accumulators, and two halves for more values. It starts from 0, so values of −0 give 0. No values give 0. |
44
+ | `mean` | `numpy.mean` of a 1-D float64 array | `sum` divided by the number of values. No values give NaN. |
45
+ | `nanmean` | `numpy.nanmean` of a 1-D float64 array | Each NaN becomes 0, `sum` adds all the values, and the sum is divided by the number of values that are not NaN. A `mean` of only the values that are not NaN can give other last bits. No values, or only NaN values, give NaN. |
46
+ | `QuantileMethod` | the `method` of `numpy.quantile` | A rule that gives the value at the quantile `q` of sorted values: `of(sorted, q)`. `q` is from 0 to 1. A `q` out of that range, or no values, throws a `RangeError`. |
47
+ | `Lower` | `method='lower'` | The value at the index `floor((n − 1)q)`. |
48
+ | `Higher` | `method='higher'` | The value at the index `ceil((n − 1)q)`. |
49
+ | `Linear` | `method='linear'`, the default of NumPy | The line between the two values around the index `(n − 1)q`, computed as NumPy's `_lerp` computes it, so the bits are NumPy's. d3-array's `quantileSorted` gives other bits for 1 value of 10. |
50
+ | `InvertedCdf` | `method='inverted_cdf'` | The nearest rank: the value at the index `ceil(nq) − 1`, and the first value when `q` is 0. |
51
+ | `ConfidenceInterval` | the `ConfidenceInterval` of `scipy.stats.bootstrap` | `low` and `high`. `isAbove(value)` is true when `low > value`, and `isBelow(value)` is true when `high < value`: the whole interval lies on one side of the value. |
52
+ | `DifferenceInterval` | the `ConfidenceInterval` of `scipy.stats.bootstrap`, with the observed statistic | A `ConfidenceInterval` of (change − baseline) with `observed`: the difference that the data gives. `new DifferenceInterval(low, high, observed)` makes one. It is data only: it has no verdict. mteb's `ChangeVerdict`, the `Interval` of relevance-filtering and the `Interval` of event-detection hold the same three values. `@zukhruf/evals` gives it in each verdict of two runs. |
53
+ | `ConfidenceIntervalMethod` | the `method` of `scipy.stats.bootstrap` | A rule that gives the confidence interval of a bootstrap distribution: `of(distribution)`. `PercentileInterval` is one. A caller with a rule of its own writes another. |
54
+ | `PercentileInterval` | `method='percentile'` of `scipy.stats.bootstrap` | The `low` and the `high` quantile of a bootstrap distribution, both read with one quantile method, as `numpy.percentile` reads them. It sorts a copy, so the distribution does not change. |
55
+ | `IidBootstrap` | `arch.bootstrap.IIDBootstrap`; `n_resamples` and `bootstrap_distribution` of SciPy | Draws `nResamples` resamples of the data, with replacement. `distribution(data, statistic)` gives the statistic of each resample. `interval(data, statistic, method)` gives the interval that a `ConfidenceIntervalMethod` reads from that distribution. Data with no items throws a `RangeError`. |
53
56
 
54
57
  The random generator is an input. `randomIndex(n)` gives an index from 0 to n − 1. Each item of a resample takes one call, in order, resample by resample, as a Python loop over the same generator does. So `(n) => random.randrange(n)` of python-random draws as CPython's `random.Random`, and a port of NumPy's `default_rng` draws as `integers(0, n, n)` when it draws one index for each call. An index out of range throws a `RangeError`.
55
58
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { IidBootstrap } from './bootstrap/iid-bootstrap.ts';
2
2
  export { ConfidenceInterval } from './interval/confidence-interval.ts';
3
3
  export type { ConfidenceIntervalMethod } from './interval/confidence-interval-method.ts';
4
+ export { DifferenceInterval } from './interval/difference-interval.ts';
4
5
  export { PercentileInterval } from './interval/percentile-interval.ts';
5
6
  export { Higher } from './quantile/higher.ts';
6
7
  export { InvertedCdf } from './quantile/inverted-cdf.ts';
@@ -8,5 +9,6 @@ export { Linear } from './quantile/linear.ts';
8
9
  export { Lower } from './quantile/lower.ts';
9
10
  export { QuantileMethod } from './quantile/quantile-method.ts';
10
11
  export { mean } from './sum/mean.ts';
12
+ export { nanmean } from './sum/nanmean.ts';
11
13
  export { sum } from './sum/sum.ts';
12
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,YAAY,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,YAAY,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  export { IidBootstrap } from "./bootstrap/iid-bootstrap.js";
2
2
  export { ConfidenceInterval } from "./interval/confidence-interval.js";
3
+ export { DifferenceInterval } from "./interval/difference-interval.js";
3
4
  export { PercentileInterval } from "./interval/percentile-interval.js";
4
5
  export { Higher } from "./quantile/higher.js";
5
6
  export { InvertedCdf } from "./quantile/inverted-cdf.js";
@@ -7,5 +8,6 @@ export { Linear } from "./quantile/linear.js";
7
8
  export { Lower } from "./quantile/lower.js";
8
9
  export { QuantileMethod } from "./quantile/quantile-method.js";
9
10
  export { mean } from "./sum/mean.js";
11
+ export { nanmean } from "./sum/nanmean.js";
10
12
  export { sum } from "./sum/sum.js";
11
13
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { ConfidenceInterval } from './confidence-interval.ts';
2
+ export declare class DifferenceInterval extends ConfidenceInterval {
3
+ readonly observed: number;
4
+ constructor(low: number, high: number, observed: number);
5
+ }
6
+ //# sourceMappingURL=difference-interval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"difference-interval.d.ts","sourceRoot":"","sources":["../../src/interval/difference-interval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAK9D,qBAAa,kBAAmB,SAAQ,kBAAkB;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAIxD"}
@@ -0,0 +1,12 @@
1
+ import { ConfidenceInterval } from "./confidence-interval.js";
2
+ // The confidence interval of (change − baseline), with the observed
3
+ // difference: the difference that the data gives. It is data only. Each
4
+ // caller reads its own verdict from isAbove and isBelow (ADR 0001).
5
+ export class DifferenceInterval extends ConfidenceInterval {
6
+ observed;
7
+ constructor(low, high, observed) {
8
+ super(low, high);
9
+ this.observed = observed;
10
+ }
11
+ }
12
+ //# sourceMappingURL=difference-interval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"difference-interval.js","sourceRoot":"","sources":["../../src/interval/difference-interval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,oEAAoE;AACpE,wEAAwE;AACxE,oEAAoE;AACpE,MAAM,OAAO,kBAAmB,SAAQ,kBAAkB;IAC/C,QAAQ,CAAS;IAE1B,YAAY,GAAW,EAAE,IAAY,EAAE,QAAgB;QACrD,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ export declare function nanmean(values: ArrayLike<number>): number;
2
+ //# sourceMappingURL=nanmean.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nanmean.d.ts","sourceRoot":"","sources":["../../src/sum/nanmean.ts"],"names":[],"mappings":"AAOA,wBAAgB,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,MAAM,CAQzD"}
@@ -0,0 +1,17 @@
1
+ import { sum } from "./sum.js";
2
+ // numpy.nanmean of a 1-D float64 array: each NaN becomes 0, sum adds all the
3
+ // values in numpy's pairwise order, and the sum is divided by the number of
4
+ // values that are not NaN. A mean of only the values that are not NaN adds in
5
+ // other blocks and can give other last bits. No values, or only NaN values,
6
+ // give NaN, as NumPy gives them.
7
+ export function nanmean(values) {
8
+ let counted = 0;
9
+ const zeroed = Float64Array.from(values, (value) => {
10
+ if (Number.isNaN(value))
11
+ return 0;
12
+ counted += 1;
13
+ return value;
14
+ });
15
+ return sum(zeroed) / counted;
16
+ }
17
+ //# sourceMappingURL=nanmean.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nanmean.js","sourceRoot":"","sources":["../../src/sum/nanmean.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAC9E,4EAA4E;AAC5E,iCAAiC;AACjC,MAAM,UAAU,OAAO,CAAC,MAAyB;IAC/C,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;QACjD,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;YAAE,OAAO,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC,CAAC;QACb,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;AAC/B,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zukhruf/statistics",
3
- "version": "0.8.7",
4
- "description": "The percentile bootstrap, NumPy's quantile methods, and numpy.sum and numpy.mean in JavaScript, to the last bit: resamples with a random generator that the caller gives, the percentile interval of their statistic, and NumPy's pairwise sum.",
3
+ "version": "0.8.9",
4
+ "description": "The percentile bootstrap, NumPy's quantile methods, and numpy.sum, numpy.mean and numpy.nanmean in JavaScript, to the last bit: resamples with a random generator that the caller gives, the percentile interval of their statistic, and NumPy's pairwise sum.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",