@numero-uno-jpn/rstats 0.5.0 → 0.6.1

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.
Files changed (168) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/README.ja.md +36 -20
  3. package/README.md +34 -18
  4. package/THIRD_PARTY_NOTICES.md +25 -5
  5. package/dist/chunks/chunk-2JCIB5H2.js +2 -0
  6. package/dist/chunks/chunk-7JVSDGQQ.js +2 -0
  7. package/dist/chunks/chunk-7NK4SA6B.js +2 -0
  8. package/dist/chunks/chunk-AJYQNFXK.js +2 -0
  9. package/dist/chunks/chunk-DRNMIEYH.js +2 -0
  10. package/dist/chunks/chunk-NAYDS7CL.js +2 -0
  11. package/dist/chunks/chunk-NOCEAM44.js +2 -0
  12. package/dist/chunks/chunk-QNAIK4PY.js +2 -0
  13. package/dist/chunks/chunk-TPC6MTYC.js +2 -0
  14. package/dist/chunks/chunk-UGUQYWRQ.js +2 -0
  15. package/dist/chunks/chunk-XM2TVD63.js +2 -0
  16. package/dist/chunks/chunk-Y4IZV7XK.js +2 -0
  17. package/dist/chunks/chunk-ZWJ42QN6.js +2 -0
  18. package/dist/descriptive/basic.d.ts +73 -0
  19. package/dist/descriptive/basic.js +256 -0
  20. package/dist/descriptive/cov.d.ts +39 -0
  21. package/dist/descriptive/cov.js +105 -0
  22. package/dist/descriptive/hist.d.ts +64 -0
  23. package/dist/descriptive/hist.js +304 -0
  24. package/dist/descriptive/moments.d.ts +63 -0
  25. package/dist/descriptive/moments.js +158 -0
  26. package/dist/descriptive/quantile.d.ts +50 -0
  27. package/dist/descriptive/quantile.js +131 -0
  28. package/dist/descriptive/rank.d.ts +23 -0
  29. package/dist/descriptive/rank.js +72 -0
  30. package/dist/descriptive/table.d.ts +54 -0
  31. package/dist/descriptive/table.js +160 -0
  32. package/dist/descriptive.js +2 -0
  33. package/dist/distributions/arcsine.d.ts +24 -0
  34. package/dist/distributions/arcsine.js +73 -0
  35. package/dist/distributions/invgamma.d.ts +29 -0
  36. package/dist/distributions/invgamma.js +85 -0
  37. package/dist/distributions/kumaraswamy.d.ts +17 -0
  38. package/dist/distributions/kumaraswamy.js +96 -0
  39. package/dist/distributions/laplace.d.ts +23 -0
  40. package/dist/distributions/laplace.js +69 -0
  41. package/dist/distributions/multinomial.d.ts +24 -0
  42. package/dist/distributions/multinomial.js +70 -0
  43. package/dist/distributions/nbeta.js +28 -10
  44. package/dist/distributions/nchisq.js +20 -3
  45. package/dist/distributions/pareto.d.ts +23 -0
  46. package/dist/distributions/pareto.js +76 -0
  47. package/dist/distributions/summary.d.ts +25 -0
  48. package/dist/distributions/summary.js +289 -0
  49. package/dist/distributions/triangular.d.ts +25 -0
  50. package/dist/distributions/triangular.js +87 -0
  51. package/dist/distributions.js +2 -0
  52. package/dist/entries/descriptive.d.ts +7 -0
  53. package/dist/entries/descriptive.js +8 -0
  54. package/dist/entries/distributions.d.ts +41 -0
  55. package/dist/entries/distributions.js +41 -0
  56. package/dist/entries/linalg.d.ts +11 -0
  57. package/dist/entries/linalg.js +11 -0
  58. package/dist/entries/numerics.d.ts +8 -0
  59. package/dist/entries/numerics.js +6 -0
  60. package/dist/entries/special.d.ts +9 -0
  61. package/dist/entries/special.js +9 -0
  62. package/dist/entries/tests.d.ts +21 -0
  63. package/dist/entries/tests.js +20 -0
  64. package/dist/htest/ansariTest.d.ts +13 -0
  65. package/dist/htest/ansariTest.js +80 -0
  66. package/dist/htest/aov.d.ts +85 -0
  67. package/dist/htest/aov.js +178 -0
  68. package/dist/htest/binomTest.d.ts +36 -0
  69. package/dist/htest/binomTest.js +121 -0
  70. package/dist/htest/cor.d.ts +14 -0
  71. package/dist/htest/cor.js +4 -3
  72. package/dist/htest/core/ansari.d.ts +18 -0
  73. package/dist/htest/core/ansari.js +121 -0
  74. package/dist/htest/core/kolmogorov.d.ts +26 -0
  75. package/dist/htest/core/kolmogorov.js +221 -0
  76. package/dist/htest/core/mantelhaen.d.ts +26 -0
  77. package/dist/htest/core/mantelhaen.js +145 -0
  78. package/dist/htest/core/shapiro.d.ts +24 -0
  79. package/dist/htest/core/shapiro.js +142 -0
  80. package/dist/htest/core/smirnov.d.ts +20 -0
  81. package/dist/htest/core/smirnov.js +75 -0
  82. package/dist/htest/fisherTest.js +134 -120
  83. package/dist/htest/groups.d.ts +20 -0
  84. package/dist/htest/groups.js +62 -0
  85. package/dist/htest/ksTest.d.ts +31 -0
  86. package/dist/htest/ksTest.js +106 -0
  87. package/dist/htest/mantelhaenTest.d.ts +26 -0
  88. package/dist/htest/mantelhaenTest.js +196 -0
  89. package/dist/htest/mcnemarTest.d.ts +26 -0
  90. package/dist/htest/mcnemarTest.js +99 -0
  91. package/dist/htest/onewayTest.d.ts +26 -0
  92. package/dist/htest/onewayTest.js +97 -0
  93. package/dist/htest/pairwise.d.ts +64 -0
  94. package/dist/htest/pairwise.js +152 -0
  95. package/dist/htest/poissonTest.d.ts +35 -0
  96. package/dist/htest/poissonTest.js +170 -0
  97. package/dist/htest/propTest.d.ts +37 -0
  98. package/dist/htest/propTest.js +164 -0
  99. package/dist/htest/rankTests.d.ts +52 -0
  100. package/dist/htest/rankTests.js +234 -0
  101. package/dist/htest/types.d.ts +2 -0
  102. package/dist/htest/types.js +6 -0
  103. package/dist/htest/varTest.d.ts +48 -0
  104. package/dist/htest/varTest.js +118 -0
  105. package/dist/htest/wilcoxTest.js +136 -174
  106. package/dist/index.d.ts +6 -50
  107. package/dist/index.js +8 -50
  108. package/dist/integrate/quadpack.d.ts +29 -0
  109. package/dist/integrate/quadpack.js +525 -0
  110. package/dist/internal/seq.d.ts +5 -0
  111. package/dist/internal/seq.js +14 -0
  112. package/dist/internal/uniroot.js +10 -71
  113. package/dist/linalg/lu.d.ts +45 -0
  114. package/dist/linalg/lu.js +88 -0
  115. package/dist/linalg/ops.d.ts +90 -0
  116. package/dist/linalg/ops.js +320 -0
  117. package/dist/linalg.js +2 -0
  118. package/dist/models/lm.d.ts +98 -0
  119. package/dist/models/lm.js +187 -0
  120. package/dist/numerics/deriv.d.ts +37 -0
  121. package/dist/numerics/deriv.js +150 -0
  122. package/dist/numerics/integrate.d.ts +91 -0
  123. package/dist/numerics/integrate.js +264 -0
  124. package/dist/numerics/interp.d.ts +103 -0
  125. package/dist/numerics/interp.js +581 -0
  126. package/dist/numerics/ode.d.ts +23 -0
  127. package/dist/numerics/ode.js +59 -0
  128. package/dist/numerics.js +2 -0
  129. package/dist/optim/localmin.d.ts +16 -0
  130. package/dist/optim/localmin.js +97 -0
  131. package/dist/random/beta.js +1 -1
  132. package/dist/random/binomial.js +1 -1
  133. package/dist/random/continuous.js +1 -1
  134. package/dist/random/extra.d.ts +33 -0
  135. package/dist/random/extra.js +62 -0
  136. package/dist/random/gamma.js +1 -1
  137. package/dist/random/hyper.js +1 -1
  138. package/dist/random/mt.js +0 -1
  139. package/dist/random/poisson.js +0 -1
  140. package/dist/random/rank.js +1 -1
  141. package/dist/random/rng.js +1 -1
  142. package/dist/random/sample.js +1 -1
  143. package/dist/rstats.js +2 -2
  144. package/dist/special/besselIK.d.ts +38 -0
  145. package/dist/special/besselIK.js +315 -0
  146. package/dist/special/besselJY.d.ts +32 -0
  147. package/dist/special/besselJY.js +508 -0
  148. package/dist/special/besselSeries.d.ts +8 -0
  149. package/dist/special/besselSeries.js +24 -0
  150. package/dist/special/beta.js +22 -5
  151. package/dist/special/choose.d.ts +75 -0
  152. package/dist/special/choose.js +233 -0
  153. package/dist/special/erf.d.ts +28 -2
  154. package/dist/special/erf.js +37 -10
  155. package/dist/special/extra.d.ts +47 -0
  156. package/dist/special/extra.js +220 -0
  157. package/dist/special/igam.d.ts +4 -0
  158. package/dist/special/igam.js +57 -2
  159. package/dist/special/incbet.js +77 -22
  160. package/dist/special/lgammaDiff.d.ts +7 -0
  161. package/dist/special/lgammaDiff.js +16 -3
  162. package/dist/special/psigamma.d.ts +48 -0
  163. package/dist/special/psigamma.js +318 -0
  164. package/dist/special/rCompatible.d.ts +8 -0
  165. package/dist/special/rCompatible.js +1 -0
  166. package/dist/special.js +2 -0
  167. package/dist/tests.js +2 -0
  168. package/package.json +26 -1
@@ -0,0 +1,11 @@
1
+ // Linear algebra (rStats.js/linalg): matrices are arrays of rows
2
+ export { crossprod, tcrossprod, backsolve, forwardsolve } from "../linalg/basic.js";
3
+ export { norm } from "../linalg/norm.js";
4
+ export { chol, chol2inv } from "../linalg/chol.js";
5
+ export { qr, qrQ, qrR, qrX, qrCoef, qrQy, qrQty, qrResid, qrFitted, qrSolve } from "../linalg/qr.js";
6
+ export { solve, det, determinant, rcond } from "../linalg/solve.js";
7
+ export { svd } from "../linalg/svd.js";
8
+ export { kappa, ginv } from "../linalg/kappa.js";
9
+ export { eigen } from "../linalg/eigen.js";
10
+ export { matMul, add, subtract, multiply, divide, outer, t, diag, cbind, rbind, matrix, kronecker, seq, } from "../linalg/ops.js";
11
+ export { lu, prcomp } from "../linalg/lu.js";
@@ -0,0 +1,8 @@
1
+ export { integrate, optimize, uniroot } from "../numerics/integrate.js";
2
+ export type { IntegrateOptions, IntegrateResult, OptimizeOptions, UnirootOptions, UnirootResult } from "../numerics/integrate.js";
3
+ export { approx, barylag, hermiteInterp, spline, splinefun, splinefunH } from "../numerics/interp.js";
4
+ export type { ApproxOptions, SplineMethod, SplineOptions, SplinefunOptions } from "../numerics/interp.js";
5
+ export { ode } from "../numerics/ode.js";
6
+ export type { OdeFunc, OdeOptions } from "../numerics/ode.js";
7
+ export { grad, hessian, jacobian } from "../numerics/deriv.js";
8
+ export type { DerivOptions } from "../numerics/deriv.js";
@@ -0,0 +1,6 @@
1
+ // Numerical methods (rStats.js/numerics): integration, optimisation, root finding, interpolation, ODEs and
2
+ // numerical derivatives
3
+ export { integrate, optimize, uniroot } from "../numerics/integrate.js";
4
+ export { approx, barylag, hermiteInterp, spline, splinefun, splinefunH } from "../numerics/interp.js";
5
+ export { ode } from "../numerics/ode.js";
6
+ export { grad, hessian, jacobian } from "../numerics/deriv.js";
@@ -0,0 +1,9 @@
1
+ export { gamma, lgamma } from "../special/gamma.js";
2
+ export { beta, lbeta } from "../special/beta.js";
3
+ export { choose, lchoose, factorial, lfactorial } from "../special/choose.js";
4
+ export type { RCompatibleOptions } from "../special/rCompatible.js";
5
+ export { digamma, trigamma, psigamma } from "../special/psigamma.js";
6
+ export { besselI, besselK, type BesselOptions } from "../special/besselIK.js";
7
+ export { besselJ, besselY } from "../special/besselJY.js";
8
+ export { erf, erfc } from "../special/erf.js";
9
+ export { gammainc, erfinv, erfcinv, perm, type GammaincResult } from "../special/extra.js";
@@ -0,0 +1,9 @@
1
+ // Special functions (rStats.js/special): gamma, beta and Bessel functions, erf, ...
2
+ export { gamma, lgamma } from "../special/gamma.js";
3
+ export { beta, lbeta } from "../special/beta.js";
4
+ export { choose, lchoose, factorial, lfactorial } from "../special/choose.js";
5
+ export { digamma, trigamma, psigamma } from "../special/psigamma.js";
6
+ export { besselI, besselK } from "../special/besselIK.js";
7
+ export { besselJ, besselY } from "../special/besselJY.js";
8
+ export { erf, erfc } from "../special/erf.js";
9
+ export { gammainc, erfinv, erfcinv, perm } from "../special/extra.js";
@@ -0,0 +1,21 @@
1
+ export { tTest, type TTestOptions, type TTestResult } from "../htest/tTest.js";
2
+ export { chisqTest, type ChisqTestOptions, type ChisqTestResult } from "../htest/chisqTest.js";
3
+ export { fisherTest, type FisherTestOptions, type FisherTestResult } from "../htest/fisherTest.js";
4
+ export { wilcoxTest, type WilcoxTestOptions, type WilcoxTestResult } from "../htest/wilcoxTest.js";
5
+ export { corTest, type CorMethod, type CorOptions, type CorTestOptions, type CorTestResult } from "../htest/cor.js";
6
+ export { pAdjust, type PAdjustMethod, type PAdjustOptions } from "../htest/pAdjust.js";
7
+ export type { Alternative, Counts, HTest, Sample } from "../htest/types.js";
8
+ export { binomTest, type BinomTestOptions, type BinomTestResult } from "../htest/binomTest.js";
9
+ export { poissonTest, type PoissonTestOptions, type PoissonTestResult } from "../htest/poissonTest.js";
10
+ export { propTest, type PropTestOptions, type PropTestResult } from "../htest/propTest.js";
11
+ export { mcnemarTest, type McnemarTestOptions, type McnemarTestResult } from "../htest/mcnemarTest.js";
12
+ export { varTest, bartlettTest, type VarTestOptions, type VarTestResult, type BartlettTestResult } from "../htest/varTest.js";
13
+ export { kruskalTest, friedmanTest, quadeTest, flignerTest, moodTest, type ChisqStatTestResult, type QuadeTestResult, type MoodTestOptions, } from "../htest/rankTests.js";
14
+ export { onewayTest, shapiroTest, type OnewayTestOptions, type OnewayTestResult } from "../htest/onewayTest.js";
15
+ export { mantelhaenTest, type MantelhaenTestOptions, type MantelhaenTestResult } from "../htest/mantelhaenTest.js";
16
+ export { ansariTest, type AnsariTestOptions } from "../htest/ansariTest.js";
17
+ export { ksTest, type KsTestOptions, type KsTestResult } from "../htest/ksTest.js";
18
+ export { pairwiseTTest, pairwiseWilcoxTest, pairwisePropTest, type PairwiseResult, type PairwiseOptions, type PairwiseTTestOptions, type PairwiseWilcoxTestOptions, type PairwisePropTestOptions, } from "../htest/pairwise.js";
19
+ export { aov, TukeyHSD, zTest, type AovResult, type TukeyHSDOptions, type TukeyHSDResult, type ZTestOptions } from "../htest/aov.js";
20
+ export type { GroupLabel } from "../htest/groups.js";
21
+ export { lm, confint, predict, type LmOptions, type LmResult, type ConfintOptions, type PredictOptions } from "../models/lm.js";
@@ -0,0 +1,20 @@
1
+ // Hypothesis tests (rStats.js/tests): R's htest results as plain objects
2
+ export { tTest } from "../htest/tTest.js";
3
+ export { chisqTest } from "../htest/chisqTest.js";
4
+ export { fisherTest } from "../htest/fisherTest.js";
5
+ export { wilcoxTest } from "../htest/wilcoxTest.js";
6
+ export { corTest } from "../htest/cor.js";
7
+ export { pAdjust } from "../htest/pAdjust.js";
8
+ export { binomTest } from "../htest/binomTest.js";
9
+ export { poissonTest } from "../htest/poissonTest.js";
10
+ export { propTest } from "../htest/propTest.js";
11
+ export { mcnemarTest } from "../htest/mcnemarTest.js";
12
+ export { varTest, bartlettTest } from "../htest/varTest.js";
13
+ export { kruskalTest, friedmanTest, quadeTest, flignerTest, moodTest, } from "../htest/rankTests.js";
14
+ export { onewayTest, shapiroTest } from "../htest/onewayTest.js";
15
+ export { mantelhaenTest } from "../htest/mantelhaenTest.js";
16
+ export { ansariTest } from "../htest/ansariTest.js";
17
+ export { ksTest } from "../htest/ksTest.js";
18
+ export { pairwiseTTest, pairwiseWilcoxTest, pairwisePropTest, } from "../htest/pairwise.js";
19
+ export { aov, TukeyHSD, zTest } from "../htest/aov.js";
20
+ export { lm, confint, predict } from "../models/lm.js";
@@ -0,0 +1,13 @@
1
+ import { type Alternative, type HTest, type Sample } from "./types.js";
2
+ /** Options for {@link ansariTest}. */
3
+ export interface AnsariTestOptions {
4
+ /** Alternative hypothesis (unambiguous abbreviations accepted). Default `"two.sided"`. */
5
+ alternative?: Alternative | "two" | "l" | "g";
6
+ /** Exact p-value. Default: exact when both samples have fewer than 50 values and there are no ties. */
7
+ exact?: boolean;
8
+ }
9
+ /**
10
+ * Ansari-Bradley test that two samples differ in scale. Equivalent to R's `ansari.test()` (without `conf.int`).
11
+ * `NaN` values are dropped.
12
+ */
13
+ export declare function ansariTest(x: Sample, y: Sample, options?: AnsariTestOptions): HTest;
@@ -0,0 +1,80 @@
1
+ // Ansari-Bradley two-sample test of scale (R's ansari.test, without the optional confidence interval).
2
+ //
3
+ // Written for rStats.js from the published test (Ansari and Bradley, Ann. Math. Stat. 31, 1960; no ported code).
4
+ // Scores min(r, N + 1 - r) of the pooled ranks r (average ranks for ties); the statistic is the sum over the first
5
+ // sample. Small samples without ties use the exact null distribution (src/htest/core/ansari.ts); the two-sided
6
+ // p-value doubles the tail on the statistic's side of the centre floor((m+1)^2/4) + floor(m n / 2)/2 (the centre
7
+ // follows R's ansari.test behaviour). Otherwise the statistic is standardised and compared with the normal, with Ansari
8
+ // and Bradley's mean and the variance of a linear rank statistic from the observed sum of squared scores (the form
9
+ // scipy.stats.ansari also uses).
10
+ import { pnorm } from "../distributions/normal.js";
11
+ import { rank } from "../internal/summary.js";
12
+ import { pansariExact } from "./core/ansari.js";
13
+ import { matchAlternative } from "./types.js";
14
+ /**
15
+ * Ansari-Bradley test that two samples differ in scale. Equivalent to R's `ansari.test()` (without `conf.int`).
16
+ * `NaN` values are dropped.
17
+ */
18
+ export function ansariTest(x, y, options = {}) {
19
+ const xs = Array.from(x).filter((v) => !Number.isNaN(v));
20
+ const ys = Array.from(y).filter((v) => !Number.isNaN(v));
21
+ const m = xs.length;
22
+ const n = ys.length;
23
+ if (m < 1)
24
+ throw new RangeError("not enough 'x' observations");
25
+ if (n < 1)
26
+ throw new RangeError("not enough 'y' observations");
27
+ const alternative = matchAlternative(options.alternative);
28
+ const N = m + n;
29
+ const r = rank(xs.concat(ys));
30
+ const a = r.map((v) => Math.min(v, N - v + 1));
31
+ let statistic = 0;
32
+ for (let i = 0; i < m; i++)
33
+ statistic += a[i];
34
+ const ties = new Set(r).size < N;
35
+ const exact = options.exact ?? (m < 50 && n < 50 && !ties);
36
+ let pValue;
37
+ if (exact && !ties) {
38
+ const upperFrom = (q) => pansariExact(q - 1, m, n, false); // P(AB >= q)
39
+ const lowerTo = (q) => pansariExact(q, m, n, true); // P(AB <= q)
40
+ if (alternative === "two.sided") {
41
+ // the smaller tail, judged by the position of the statistic against the centre of the distribution (the centre
42
+ // follows R's ansari.test behaviour)
43
+ const centre = Math.floor((m + 1) ** 2 / 4) + Math.floor((m * n) / 2) / 2;
44
+ pValue = Math.min(1, 2 * (statistic > centre ? upperFrom(statistic) : lowerTo(statistic)));
45
+ }
46
+ else if (alternative === "less")
47
+ pValue = upperFrom(statistic);
48
+ else
49
+ pValue = lowerTo(statistic);
50
+ }
51
+ else {
52
+ // mean and variance with the sum of the scores at its value without ties (N (N + 2) / 4 for even N,
53
+ // (N + 1)^2 / 4 for odd N), and the sum of their squares as observed
54
+ let sq = 0;
55
+ for (const v of a)
56
+ sq += v * v;
57
+ const even = N % 2 === 0;
58
+ const mean = even ? (m * (N + 2)) / 4 : (m * (N + 1) ** 2) / (4 * N);
59
+ const variance = even
60
+ ? (m * n * (16 * sq - N * (N + 2) ** 2)) / (16 * N * (N - 1))
61
+ : (m * n * (16 * N * sq - (N + 1) ** 4)) / (16 * N * N * (N - 1));
62
+ const z = (statistic - mean) / Math.sqrt(variance);
63
+ // large AB means the first sample is concentrated in the middle: smaller scale
64
+ pValue =
65
+ alternative === "two.sided"
66
+ ? 2 * Math.min(pnorm(z), pnorm(z, { lowerTail: false }))
67
+ : alternative === "less"
68
+ ? pnorm(z, { lowerTail: false })
69
+ : pnorm(z);
70
+ }
71
+ return {
72
+ method: "Ansari-Bradley test",
73
+ alternative,
74
+ statistic,
75
+ statisticName: "AB",
76
+ pValue,
77
+ nullValue: 1,
78
+ nullValueName: "ratio of scales",
79
+ };
80
+ }
@@ -0,0 +1,85 @@
1
+ import { type GroupLabel } from "./groups.js";
2
+ import { type Alternative, type HTest, type Sample } from "./types.js";
3
+ /** Result of {@link aov}: the one-way ANOVA table, rows "between groups" and "residuals". */
4
+ export interface AovResult {
5
+ /** Degrees of freedom `[k - 1, N - k]`. */
6
+ df: [number, number];
7
+ /** Sums of squares `[between, residual]`. */
8
+ sumSq: [number, number];
9
+ /** Mean squares `[between, residual]`. */
10
+ meanSq: [number, number];
11
+ /** F statistic. */
12
+ fValue: number;
13
+ /** p-value of the F test. */
14
+ pValue: number;
15
+ }
16
+ /**
17
+ * One-way analysis of variance. Equivalent to the table of R's `summary(aov(y ~ g))` for one factor.
18
+ *
19
+ * @param x An array of samples (groups), or one sample with group labels `g`.
20
+ * @param g Group labels, parallel to `x`.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const r = aov([[2.9, 3.0, 2.5, 2.6, 3.2], [3.8, 2.7, 4.0, 2.4], [2.8, 3.4, 3.7, 2.2, 2.0]]);
25
+ * r.fValue; // 0.5600732600732597
26
+ * r.pValue; // 0.586632991041738
27
+ * ```
28
+ */
29
+ export declare function aov(x: Sample | readonly Sample[], g?: readonly GroupLabel[]): AovResult;
30
+ /** Options for {@link TukeyHSD}. */
31
+ export interface TukeyHSDOptions {
32
+ /** Family-wise confidence level. Default `0.95`. */
33
+ confLevel?: number;
34
+ }
35
+ /** Result of {@link TukeyHSD}: one entry per pair of groups, in R's order (2-1, 3-1, ..., k-1, 3-2, ...). */
36
+ export interface TukeyHSDResult {
37
+ /**
38
+ * Labels of the comparisons, `"a-b"`: the group labels when given, otherwise the positions of the samples in the
39
+ * list (from 1). Groups without data are left out, as in R.
40
+ */
41
+ names: string[];
42
+ /** The group compared (1-based position among the groups compared, i > j). */
43
+ i: number[];
44
+ /** The group it is compared with (1-based index). */
45
+ j: number[];
46
+ /** Difference of means, group i minus group j. */
47
+ diff: number[];
48
+ /** Lower ends of the simultaneous intervals. */
49
+ lwr: number[];
50
+ /** Upper ends. */
51
+ upr: number[];
52
+ /** p-values adjusted for the multiple comparisons. */
53
+ pAdj: number[];
54
+ }
55
+ /**
56
+ * Tukey's honest significant differences between the group means of a one-way ANOVA (Tukey-Kramer for unequal
57
+ * sizes). Equivalent to R's `TukeyHSD(aov(y ~ g))`.
58
+ *
59
+ * @param x An array of samples (groups), or one sample with group labels `g` (then `options` comes third).
60
+ */
61
+ export declare function TukeyHSD(x: Sample | readonly Sample[], g?: readonly GroupLabel[] | TukeyHSDOptions, options?: TukeyHSDOptions): TukeyHSDResult;
62
+ /** Options for {@link zTest}. */
63
+ export interface ZTestOptions {
64
+ /** Known standard deviation of the population of `x` (required). */
65
+ sigmaX?: number;
66
+ /** Known standard deviation of the population of `y` (required with `y`). */
67
+ sigmaY?: number;
68
+ /** Mean (or difference of means) under the null hypothesis. Default `0`. */
69
+ mu?: number;
70
+ /** Alternative hypothesis (unambiguous abbreviations accepted). Default `"two.sided"`. */
71
+ alternative?: Alternative | "two" | "l" | "g";
72
+ /** Confidence level of the interval. Default `0.95`. */
73
+ confLevel?: number;
74
+ }
75
+ /**
76
+ * z test for the mean of one sample, or the difference of the means of two, with known standard deviations.
77
+ * Equivalent to `BSDA::z.test()` (the open end of a one-sided interval is ±Infinity here, NA in BSDA). `NaN` values
78
+ * are dropped.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * zTest([5.1, 4.9, 5.6, 5.8, 6.0], { mu: 5, sigmaX: 0.5 }).pValue;
83
+ * ```
84
+ */
85
+ export declare function zTest(x: Sample, y?: Sample | ZTestOptions, options?: ZTestOptions): HTest;
@@ -0,0 +1,178 @@
1
+ // One-way analysis of variance (the table of R's summary(aov(y ~ g))), Tukey's honest significant differences (R's
2
+ // TukeyHSD) and the z test with known standard deviations (as BSDA's z.test).
3
+ //
4
+ // Written for rStats.js from the textbook formulas. The sums of squares are accumulated in
5
+ // double-double: between groups sum n_i (m_i - m)^2, within groups sum (x - m_i)^2, so a within sum that is exactly
6
+ // 0 stays 0 (F = Inf; R's QR leaves rounding residue there). TukeyHSD uses the Tukey-Kramer standard error
7
+ // sqrt(MSE / 2 (1/n_i + 1/n_j)) with the studentized range distribution for the interval and the adjusted p-value.
8
+ // zTest is the textbook z test (standard error sigma / sqrt(n), or sqrt(sigma_x^2/n_x + sigma_y^2/n_y) for two
9
+ // samples, normal quantiles for the interval around the estimate); its input checks (at least 3 observations,
10
+ // confLevel allowed in the closed [0, 1]) follow BSDA's documented/observed behaviour, with messages of our own.
11
+ import { pf1 } from "../distributions/f.js";
12
+ import { pnorm, qnorm } from "../distributions/normal.js";
13
+ import { ptukey, qtukey } from "../distributions/tukey.js";
14
+ import { meanDD } from "../internal/summary.js";
15
+ import { ddAdd, ddMul, ddSub } from "../special/dd.js";
16
+ import { labelledGroups, toGroups } from "./groups.js";
17
+ import { matchAlternative } from "./types.js";
18
+ function sums(groups) {
19
+ const all = groups.flat();
20
+ const m = meanDD(all);
21
+ let ssb = [0, 0];
22
+ let ssw = [0, 0];
23
+ const means = [];
24
+ for (const g of groups) {
25
+ const mi = meanDD(g);
26
+ means.push(mi[0]);
27
+ const d = ddSub(mi, m);
28
+ ssb = ddAdd(ssb, ddMul(ddMul(d, d), [g.length, 0]));
29
+ for (const v of g) {
30
+ const e = ddSub([v, 0], mi);
31
+ ssw = ddAdd(ssw, ddMul(e, e));
32
+ }
33
+ }
34
+ return { ssb: ssb[0], ssw: ssw[0], means };
35
+ }
36
+ /**
37
+ * One-way analysis of variance. Equivalent to the table of R's `summary(aov(y ~ g))` for one factor.
38
+ *
39
+ * @param x An array of samples (groups), or one sample with group labels `g`.
40
+ * @param g Group labels, parallel to `x`.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const r = aov([[2.9, 3.0, 2.5, 2.6, 3.2], [3.8, 2.7, 4.0, 2.4], [2.8, 3.4, 3.7, 2.2, 2.0]]);
45
+ * r.fValue; // 0.5600732600732597
46
+ * r.pValue; // 0.586632991041738
47
+ * ```
48
+ */
49
+ export function aov(x, g) {
50
+ const groups = toGroups(x, g);
51
+ const k = groups.length;
52
+ if (k < 2)
53
+ throw new RangeError("contrasts can be applied only to factors with 2 or more levels");
54
+ const N = groups.reduce((a, s) => a + s.length, 0);
55
+ const { ssb, ssw } = sums(groups);
56
+ const df1 = k - 1;
57
+ const df2 = N - k;
58
+ const msb = ssb / df1;
59
+ const msw = ssw / df2;
60
+ const fValue = msb / msw;
61
+ return {
62
+ df: [df1, df2],
63
+ sumSq: [ssb, ssw],
64
+ meanSq: [msb, msw],
65
+ fValue,
66
+ pValue: df2 > 0 ? pf1(fValue, df1, df2, false, false) : NaN,
67
+ };
68
+ }
69
+ /**
70
+ * Tukey's honest significant differences between the group means of a one-way ANOVA (Tukey-Kramer for unequal
71
+ * sizes). Equivalent to R's `TukeyHSD(aov(y ~ g))`.
72
+ *
73
+ * @param x An array of samples (groups), or one sample with group labels `g` (then `options` comes third).
74
+ */
75
+ export function TukeyHSD(x, g, options = {}) {
76
+ let labels;
77
+ if (g !== undefined && !Array.isArray(g))
78
+ options = g;
79
+ else
80
+ labels = g;
81
+ // names follow the groups: a label (or list position) whose values are all missing has no group, as R drops the
82
+ // unused factor level
83
+ const { labels: names, groups } = labelledGroups(x, labels);
84
+ const k = groups.length;
85
+ if (k < 2)
86
+ throw new RangeError("contrasts can be applied only to factors with 2 or more levels");
87
+ const confLevel = options.confLevel ?? 0.95;
88
+ const N = groups.reduce((a, s) => a + s.length, 0);
89
+ const df = N - k;
90
+ const { ssw, means } = sums(groups);
91
+ const mse = ssw / df;
92
+ const q = qtukey(confLevel, k, df);
93
+ const out = { names: [], i: [], j: [], diff: [], lwr: [], upr: [], pAdj: [] };
94
+ for (let b = 0; b < k - 1; b++) {
95
+ for (let a = b + 1; a < k; a++) {
96
+ const diff = means[a] - means[b];
97
+ const se = Math.sqrt((mse / 2) * (1 / groups[a].length + 1 / groups[b].length));
98
+ out.names.push(`${names[a]}-${names[b]}`);
99
+ out.i.push(a + 1);
100
+ out.j.push(b + 1);
101
+ out.diff.push(diff);
102
+ out.lwr.push(diff - q * se);
103
+ out.upr.push(diff + q * se);
104
+ out.pAdj.push(ptukey(Math.abs(diff) / se, k, df, { lowerTail: false }));
105
+ }
106
+ }
107
+ return out;
108
+ }
109
+ /**
110
+ * z test for the mean of one sample, or the difference of the means of two, with known standard deviations.
111
+ * Equivalent to `BSDA::z.test()` (the open end of a one-sided interval is ±Infinity here, NA in BSDA). `NaN` values
112
+ * are dropped.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * zTest([5.1, 4.9, 5.6, 5.8, 6.0], { mu: 5, sigmaX: 0.5 }).pValue;
117
+ * ```
118
+ */
119
+ export function zTest(x, y, options = {}) {
120
+ let ys;
121
+ if (y !== undefined && !ArrayBuffer.isView(y) && !Array.isArray(y))
122
+ options = y;
123
+ else
124
+ ys = y;
125
+ const { sigmaX, sigmaY } = options;
126
+ const mu = options.mu ?? 0;
127
+ if (sigmaX === undefined && ys === undefined)
128
+ throw new RangeError("sigmaX (the known standard deviation of x) is required");
129
+ if (sigmaX === undefined || (ys !== undefined && sigmaY === undefined)) {
130
+ throw new RangeError("sigmaX and sigmaY are both required for two samples");
131
+ }
132
+ if (Number.isNaN(mu))
133
+ throw new RangeError("mu must be a number");
134
+ const alternative = matchAlternative(options.alternative);
135
+ const confLevel = options.confLevel ?? 0.95;
136
+ if (!(confLevel >= 0 && confLevel <= 1))
137
+ throw new RangeError("confLevel must be between 0 and 1");
138
+ const xs = Array.from(x).filter((v) => !Number.isNaN(v));
139
+ const yv = ys === undefined ? undefined : Array.from(ys).filter((v) => !Number.isNaN(v));
140
+ if (xs.length < 3)
141
+ throw new RangeError("x needs at least 3 non-missing values");
142
+ if (yv !== undefined && yv.length < 3)
143
+ throw new RangeError("y needs at least 3 non-missing values");
144
+ const meanX = meanDD(xs)[0];
145
+ const meanY = yv === undefined ? NaN : meanDD(yv)[0];
146
+ const se = yv === undefined ? sigmaX / Math.sqrt(xs.length) : Math.sqrt(sigmaX ** 2 / xs.length + sigmaY ** 2 / yv.length);
147
+ const target = yv === undefined ? meanX : meanX - meanY;
148
+ const z = (target - mu) / se;
149
+ let pValue;
150
+ let confInt;
151
+ if (alternative === "less") {
152
+ pValue = pnorm(z);
153
+ confInt = [-Infinity, target + qnorm(confLevel) * se];
154
+ }
155
+ else if (alternative === "greater") {
156
+ pValue = pnorm(z, { lowerTail: false });
157
+ confInt = [target - qnorm(confLevel) * se, Infinity];
158
+ }
159
+ else {
160
+ pValue = 2 * pnorm(-Math.abs(z));
161
+ const half = qnorm(1 - (1 - confLevel) / 2) * se;
162
+ confInt = [target - half, target + half];
163
+ }
164
+ const twoSample = yv !== undefined;
165
+ return {
166
+ method: twoSample ? "Two-sample z-Test" : "One-sample z-Test",
167
+ alternative,
168
+ statistic: z,
169
+ statisticName: "z",
170
+ pValue,
171
+ confInt,
172
+ confLevel,
173
+ estimate: twoSample ? [meanX, meanY] : meanX,
174
+ estimateNames: twoSample ? ["mean of x", "mean of y"] : "mean of x",
175
+ nullValue: mu,
176
+ nullValueName: twoSample ? "difference in means" : "mean",
177
+ };
178
+ }
@@ -0,0 +1,36 @@
1
+ import { type Alternative, type HTest } from "./types.js";
2
+ /** Options for {@link binomTest}. */
3
+ export interface BinomTestOptions {
4
+ /** Hypothesized probability of success. Default `0.5`. */
5
+ p?: number;
6
+ /** Alternative hypothesis (unambiguous abbreviations accepted). Default `"two.sided"`. */
7
+ alternative?: Alternative | "two" | "l" | "g";
8
+ /** Confidence level of the interval. Default `0.95`. */
9
+ confLevel?: number;
10
+ }
11
+ /** Result of {@link binomTest}. */
12
+ export interface BinomTestResult extends HTest {
13
+ /** Number of trials (`parameterName` is `"number of trials"`). */
14
+ parameter: number;
15
+ /** Clopper-Pearson interval for the probability of success. */
16
+ confInt: [number, number];
17
+ confLevel: number;
18
+ /** Observed proportion of successes. */
19
+ estimate: number;
20
+ nullValue: number;
21
+ }
22
+ /**
23
+ * Exact test of a simple null hypothesis about the probability of success in Bernoulli trials. Equivalent to R's
24
+ * `binom.test()`.
25
+ *
26
+ * @param x Number of successes, or `[successes, failures]`.
27
+ * @param n Number of trials (ignored when `x` has two elements; may then be omitted and the options passed in its
28
+ * place).
29
+ * @param options See {@link BinomTestOptions}.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * binomTest(682, 925, { p: 0.75 }).pValue; // 0.3824916
34
+ * ```
35
+ */
36
+ export declare function binomTest(x: number | readonly [number, number], n?: number | BinomTestOptions, options?: BinomTestOptions): BinomTestResult;
@@ -0,0 +1,121 @@
1
+ // Exact binomial test (R's binom.test).
2
+ //
3
+ // Written for rStats.js from the textbook construction and R's documented behaviour. The two-sided p-value adds the
4
+ // probabilities of all outcomes no more likely than the observed one, with a relative slack of 1e-7 on that
5
+ // comparison so that outcomes of equal probability are not split by rounding (R's convention). The observed side is
6
+ // taken as a tail of the distribution function and the opposite side as the tail made of the outcomes that pass the
7
+ // comparison (counted one by one). The confidence interval is Clopper and Pearson's (Biometrika 26, 1934), from beta
8
+ // quantiles.
9
+ import { dbinom1, pbinom1 } from "../distributions/binomial.js";
10
+ import { qbeta1 } from "../distributions/beta.js";
11
+ import { checkConfLevelOpen, matchAlternative } from "./types.js";
12
+ /** Relative slack when comparing outcome probabilities with the observed one */
13
+ const SLACK = 1 + 1e-7;
14
+ function isCount(v) {
15
+ return Number.isFinite(v) && v >= 0 && Math.abs(v - Math.round(v)) <= 1e-7 * Math.max(1, Math.abs(v));
16
+ }
17
+ /**
18
+ * Two-sided p-value: the total probability of the outcomes no more likely than x (within the relative slack). The
19
+ * observed side is one tail of the distribution function; on the opposite side the qualifying outcomes are counted,
20
+ * and as they are the most extreme ones there, their mass is again a tail probability.
21
+ */
22
+ function twoSidedP(x, n, p) {
23
+ if (p === 0)
24
+ return x === 0 ? 1 : 0;
25
+ if (p === 1)
26
+ return x === n ? 1 : 0;
27
+ const mean = n * p;
28
+ if (x === mean)
29
+ return 1;
30
+ const cut = dbinom1(x, n, p, false) * SLACK;
31
+ let count = 0;
32
+ if (x < mean) {
33
+ for (let i = Math.ceil(mean); i <= n; i++)
34
+ if (dbinom1(i, n, p, false) <= cut)
35
+ count++;
36
+ const other = count === 0 ? 0 : pbinom1(n - count, n, p, false, false);
37
+ return Math.min(1, pbinom1(x, n, p, true, false) + other);
38
+ }
39
+ for (let i = 0; i <= Math.floor(mean); i++)
40
+ if (dbinom1(i, n, p, false) <= cut)
41
+ count++;
42
+ const other = count === 0 ? 0 : pbinom1(count - 1, n, p, true, false);
43
+ return Math.min(1, pbinom1(x - 1, n, p, false, false) + other);
44
+ }
45
+ /**
46
+ * Exact test of a simple null hypothesis about the probability of success in Bernoulli trials. Equivalent to R's
47
+ * `binom.test()`.
48
+ *
49
+ * @param x Number of successes, or `[successes, failures]`.
50
+ * @param n Number of trials (ignored when `x` has two elements; may then be omitted and the options passed in its
51
+ * place).
52
+ * @param options See {@link BinomTestOptions}.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * binomTest(682, 925, { p: 0.75 }).pValue; // 0.3824916
57
+ * ```
58
+ */
59
+ export function binomTest(x, n, options = {}) {
60
+ let xs;
61
+ let ns;
62
+ if (typeof x !== "number") {
63
+ if (x.length !== 2)
64
+ throw new RangeError("incorrect length of 'x'");
65
+ if (n !== undefined && typeof n !== "number")
66
+ options = n;
67
+ if (!isCount(x[0]) || !isCount(x[1]))
68
+ throw new RangeError("'x' must be nonnegative and integer");
69
+ xs = Math.round(x[0]);
70
+ ns = Math.round(x[0]) + Math.round(x[1]);
71
+ }
72
+ else {
73
+ if (typeof n !== "number")
74
+ throw new TypeError("'n' is required when 'x' is a single number");
75
+ if (!isCount(x))
76
+ throw new RangeError("'x' must be nonnegative and integer");
77
+ xs = Math.round(x);
78
+ if (!(isCount(n) && Math.round(n) >= xs && n > 0))
79
+ throw new RangeError("'n' must be a positive integer >= 'x'");
80
+ ns = Math.round(n);
81
+ }
82
+ const p = options.p ?? 0.5;
83
+ if (!(p >= 0 && p <= 1))
84
+ throw new RangeError("'p' must be a single number between 0 and 1");
85
+ const alternative = matchAlternative(options.alternative);
86
+ const confLevel = options.confLevel ?? 0.95;
87
+ checkConfLevelOpen(confLevel);
88
+ let pValue;
89
+ if (alternative === "less")
90
+ pValue = pbinom1(xs, ns, p, true, false);
91
+ else if (alternative === "greater")
92
+ pValue = pbinom1(xs - 1, ns, p, false, false);
93
+ else
94
+ pValue = twoSidedP(xs, ns, p);
95
+ const lower = (alpha) => (xs === 0 ? 0 : qbeta1(alpha, xs, ns - xs + 1, true, false));
96
+ const upper = (alpha) => (xs === ns ? 1 : qbeta1(1 - alpha, xs + 1, ns - xs, true, false));
97
+ let confInt;
98
+ if (alternative === "less")
99
+ confInt = [0, upper(1 - confLevel)];
100
+ else if (alternative === "greater")
101
+ confInt = [lower(1 - confLevel), 1];
102
+ else {
103
+ const alpha = (1 - confLevel) / 2;
104
+ confInt = [lower(alpha), upper(alpha)];
105
+ }
106
+ return {
107
+ method: "Exact binomial test",
108
+ alternative,
109
+ statistic: xs,
110
+ statisticName: "number of successes",
111
+ parameter: ns,
112
+ parameterName: "number of trials",
113
+ pValue,
114
+ confInt,
115
+ confLevel,
116
+ estimate: xs / ns,
117
+ estimateNames: "probability of success",
118
+ nullValue: p,
119
+ nullValueName: "probability of success",
120
+ };
121
+ }
@@ -1,3 +1,4 @@
1
+ import { type DD } from "../special/dd.js";
1
2
  import { type Alternative, type HTest, type Sample } from "./types.js";
2
3
  /** Correlation coefficient: Pearson's r, Kendall's tau or Spearman's rho. */
3
4
  export type CorMethod = "pearson" | "kendall" | "spearman";
@@ -52,6 +53,18 @@ export interface CorTestResult extends HTest {
52
53
  * @returns The correlation coefficient.
53
54
  */
54
55
  export declare function cor(x: Sample, y: Sample, options?: CorOptions): number;
56
+ /** Pearson's correlation coefficient in double-double (so 1 - r is computed without cancellation near perfect correlation) */
57
+ export declare function pearsonDD(x: readonly number[], y: readonly number[]): DD;
58
+ interface KendallStats {
59
+ /** Number of concordant pairs minus number of discordant pairs */
60
+ s: number;
61
+ tau: number;
62
+ ties: boolean;
63
+ tx: number[];
64
+ ty: number[];
65
+ }
66
+ /** Count concordant and discordant pairs (O(n^2)). Two Infs are tied */
67
+ export declare function kendall(x: readonly number[], y: readonly number[]): KendallStats;
55
68
  /**
56
69
  * Test for correlation between paired samples. Equivalent to R's `cor.test()`.
57
70
  *
@@ -79,3 +92,4 @@ export declare function cor(x: Sample, y: Sample, options?: CorOptions): number;
79
92
  * ```
80
93
  */
81
94
  export declare function corTest(x: Sample, y: Sample, options?: CorTestOptions): CorTestResult;
95
+ export {};