Releases: simple-statistics/simple-statistics
Release list
v7.12.0
Minor Changes
- e74db06:
sampleSkewnessaccepts abiasedflag. Passingtruereturns the biased coefficient, the population moment ratiom3 / m2^(3/2), which is what R reports and whatscipy.stats.skewreturns by default. The existing adjusted Fisher-Pearson coefficient stays the default and is unchanged, so this is opt-in. Closes #167. - cc052d6: Add
scaledRootMeanSquare, an equivalent way of computing the root mean square for values whose squares leave floating point range.rootMeanSquaresums the squares directly, so it returnsInfinityabove roughly 1e154 and0below roughly 1e-162. The new function divides through by the largest magnitude first.rootMeanSquareis unchanged, following the same split asgeometricMeanandlogAverage. - 2239688: Add
weightedLinearRegression, which fits a line by weighted least squares, the same thing R'slm()does when given aweightsargument.linearRegressionis the special case where every weight is equal, and it is unchanged. Validation reuses the same helper as the other weighted functions. Closes #48.
Patch Changes
- d4adf28: Correct the chi-squared critical value at 7 degrees of freedom and an upper tail of 0.99.
chiSquaredDistributionTable[7][0.99]carried 1.25, where the exact value is 1.23904 and rounds to 1.24 at the table's two decimal places. At 1.25 the tabulated upper tail is 0.98973 rather than 0.99.chiSquaredGoodnessOfFitcompares its statistic against this cell, so a statistic in [1.24, 1.25) was reported as not significant at that level when the correct conclusion is the opposite. - b6debf9: Correct
gammafor small arguments. Nemes' approximation is asymptotic, dividing its terms by powers ofn - 3/4, so the series stops converging once the argument is small. Applied directly it returned 2.8 forgamma(1.01)against a true value of 0.994, and 1.2128 forgamma(1.1)against 0.951. Arguments in(0, 1)were already lifted by a two-step recurrence; that lift now runs generally, raising the argument until the expansion converges. Worst relative error over(0, 30]goes from 1.8 to 1.9e-13, and over[-11, 0)from 0.64 to 2.8e-13, since negative arguments reach the expansion through Euler's reflection formula. The two@examplevalues forgamma(11.5)andgamma(-11.5)recorded the old error and have been updated. - cbbae6d: Fix
linearRegressionlosing precision when the x values share a large offset. The one-pass normal equations subtract two large and nearly equal quantities, so cancellation destroys the variance: on a perfect line the slope came back 22% low for x near 1e8, changed sign at 1e9, and wasInfinityat 1e10. Timestamps reach this in ordinary use, and withDate.now()as x the slope was 69% wrong. The cross products are now accumulated from deviations about the means, which is whatweightedLinearRegressionandsampleVariancealready do, at the cost of a second pass over the data.weightedLinearRegressiondocumentslinearRegressionas the special case where every weight is equal; the two disagreed at large x and now agree. - 3ca20c8: Correct what
mode,modeSortedandmodeFastsay about ties. All three promised "in the event of a tie, this algorithm will return the most recently seen mode", which none of them does, and they do not agree with each other either.modesorts its input andmodeSortedexpects sorted input, so in both cases equal values are adjacent and a tie resolves to the smallest tied value.modeFastwalks the input keeping a strict maximum, so a tie resolves to whichever value reaches the highest count first:mode([5, 5, 2, 2])is2whilemodeFast([5, 5, 2, 2])is5. Each docstring now states its own rule and points at the difference, since the three are presented as interchangeable. Tests pin all three behaviours; no behaviour changed. - a48dc26: Fix
PerceptronModel.trainwriting through to the caller's feature array. When the feature length did not match the current weight length,trainassigned the caller's array tothis.weightsdirectly, so the weight-update loop mutated the caller's data in place and the model kept sharing identity with that array.train([1, 2, 3], 0)left the caller holding[0, 0, 0], and a later write to the caller's array silently rewrote the trained weights.trainnow copies the array, matching the defensive copying already used inshuffleandnumericSort. - 02907dd: fix: permutationTest now keeps the original sample sizes when permuting unequal-length samples
- ec2cfc7: Exclude a point from its own cluster when computing its silhouette.
a(i), the mean intra-cluster distance, was summed over every member of the point's own cluster including the point itself, whose distance to itself is zero, and divided by the full cluster size rather than one less. That understatesa(i)by a factor of(n-1)/nfor a cluster ofnpoints, sosilhouetteandsilhouetteMetricreturned inflated values for every point in a cluster with more than one member. On the fixture already in the test suite, points[[0.2], [0.4], [0.6], [0.8]]labelled[0, 0, 1, 1]returned[0.8, 2/3, 2/3, 0.8]where the definition gives[0.6, 1/3, 1/3, 0.6], which is what scikit-learn'ssilhouette_samplesreturns for the same input. The distortion scales with cluster size, so it is not uniform across clusterings and can affect comparisons between them.b(i), the mean distance to the nearest other cluster, is unchanged: the point is never a member of that group.
v7.11.0
Minor Changes
- 5c54a63: Add
normalDistribution(x, mean, standardDeviation, cumulative), the equivalent of spreadsheetNORM.DIST. Withcumulativefalse (the default) it returns the normal probability density, which the library previously had no function for; withcumulativetrue it returns the cumulative probability viaerrorFunction, avoiding the two-decimal z rounding and four-decimal table values that boundcumulativeStdNormalProbability's precision.
Patch Changes
- 5b73a3c: Correct the chi-squared critical value at 25 degrees of freedom and the 0.10 significance level.
chiSquaredDistributionTable[25][0.1]carried 34.28 where the exact upper 10% quantile is 34.3816, which rounds to 34.38 at the table's two decimal places.chiSquaredGoodnessOfFitcompares its statistic against that cell, so a statistic falling between 34.28 and 34.3816 was reported as significant at the 0.10 level when the correct conclusion is that the null hypothesis cannot be rejected. Checking all 407 entries against exact quantiles found this to be the only cell out of step; the neighbouring rows, 33.20 at 24 degrees of freedom and 35.56 at 26, already matched. - e8518fa: Correct six entries at the top of
standardNormalTable. The table is built from a Taylor series truncated at 15 terms, which falls short of four-decimal precision above z = 2.9:cumulativeStdNormalProbability(3)returned 0.9986 where the published value is 0.9987, and z = 2.94, 2.96, 2.98, 3.05 and 3.08 were each low by one in the fourth decimal. Thirty terms converge across the whole domain of the table.
v7.10.2
Patch Changes
- 7063073: Make
approxEqual'stoleranceparameter optional in its type declaration. The implementation defaults it to the library'sepsilon(0.0001), but the declaration required all three arguments, so TypeScript rejected the two-argument call the runtime supports. Runtime behavior is unchanged. - 62d100a: Correct two JSDoc example values that the implementation does not produce:
interquartileRange([0, 1, 2, 3])returns 1.5 under the type-7 quantile interpolation the library switched to, not the documented 2, andweightedQuantile([1, 2, 3], [1, 1, 2], 0.5)returns 2 — the value its own tests assert — not the documented 3. Documentation-only; runtime behavior is untouched. - 08369c8: Declare that
jenkscan returnnull. The implementation returnsnullwhenevernClassesis greater than the number of data points — since the function's introduction — but the type declaration promised a plainnumber[], so TypeScript consumers understrictNullChecksgot no warning before dereferencing the result. Runtime behavior is unchanged; only the declaration and docstring now state thenullcase. - f25c2ba: Repair JSDoc that misrenders on the documentation site:
quantileRankandquantileRankSortednow document theirvalueparameter (it was missing, and the@returnsdescription read "value value"),jenks's example is tagged@exampleso it renders as an example instead of leaking into the@returnsdescription, andkMeansCluster's documented example output gets the missing comma that made it invalid JavaScript. Documentation-only; runtime behavior is untouched. - 32096eb: Correct the third parameter of the
permutationTesttype declaration. It was namedstringand typedstring, so TypeScript consumers sawpermutationTest(sampleX, sampleY, string?: string, ...)with no indication of which values are accepted. It is nowalternative?: "two_side" | "greater" | "less", matching the JSDoc and the three values the implementation accepts before it throws. Runtime behavior is unchanged. The rename is not breaking, since TypeScript binds parameters positionally, but the narrowed type will newly reject a call that passes an arbitrarystring— such a call already threw at runtime. - f59d6d2: Correct
permutationTest's JSDoc to name thealternativevalue the implementation accepts. The docs described the two-sided test astwo_tailand'two_sided' (default), but passing either throws`alternative` must be either 'two_side', 'greater', or 'less'.— only'two_side'is accepted. Documentation-only change; runtime behavior is untouched.
v7.10.1
Patch Changes
- 894958a: Fix
chiSquaredGoodnessOfFit()reporting a fit it never measured. Collapsing a sparse class dropped the last class instead of the one that had just been merged, so observations were discarded and others double counted; an observation past the end of the hypothesized distribution had no expected frequency at all, which made the statisticNaN; andcriticalValue < NaNisfalse, the same answer the function gives for a good fit. Degrees of freedom and significance levels the table does not cover now raise a descriptive error instead of aTypeErroror a silentfalse. - a078231: Declare that
PerceptronModel#predictandPerceptronModel#traincan returnnull.predictreturnsnullwhen the feature array's length differs from what the model was trained on, andtrainreturnsnullwhen the label is not 0 or 1 — both since their introduction — but the type declarations promised plainnumberandPerceptronModel, so TypeScript consumers understrictNullChecksgot no warning before dereferencing the result. Runtime behavior is unchanged; only the declarations and docstrings now state thenullcases.
v7.10.0
Minor Changes
-
2149cff: Fix
poissonDistribution()andbinomialDistribution()returning a truncated table ending inInfinityorNaN. Both built each cell from a power and a factorial (or a binomial coefficient) that leave floating-point range long before their product does, so the cumulative-probability stopping rule was satisfied by a non-finite sum instead of by the distribution:poissonDistribution(200)returned 135 cells covering 0.000045% of the distribution, andbinomialDistribution(10000, 0.5)returned 135 cells covering none of it. Cells are now taken throughgammaln, and a table that cannot be completed returnsundefinedrather than a partial one.NOTE: this is tagged as a minor change but you should be aware that it does change behavior
forbinomialDistribution. For most users this won't be a big deal.- Both functions now return
undefinedin cases where they used to return an array of non-finite cells.binomialDistribution(5, NaN)returned[NaN]and now returnsundefined. Their TypeScript declarations widen tonumber[] | undefined. - Evaluating cells through logarithms costs a precision where the old product form was exact:
binomialDistribution(2, 0.5)returns[0.25000000000000006, 0.5000000000000006, 0.25000000000000006]rather than[0.25, 0.5, 0.25]. This precision loss is small but if you're comparing exact results, it may require updates or rounding.
- Both functions now return
Patch Changes
-
13530b2: Fix wilcoxon rank-sum test behavior
This fixes a bug in which the tie averaging in
wilcoxonRankSumwas
incorrect and would return an unrelated position. -
0779f22: Fix
sampleRankCorrelationreturning different results for the same data depending on the order the pairs are listed in. Tied values were given distinct consecutive ranks broken by original array position, rather than sharing the average of the ranks they span as Spearman's rho requires. Reordering rows could change the magnitude and even the sign of the result. Tied values now receive midranks, so the correlation depends only on the paired data. As a consequence an input with no rank variance — every value tied — now correctly returnsNaNinstead of reporting near-perfect correlation. Results for inputs with no ties are unchanged.
v7.9.3
Patch Changes
- 2a98671: Mark the package as
"type": "module"and rename the CommonJS bundle todist/simple-statistics.cjs. Consumers resolve through theexportsmap, so bothimport "simple-statistics"andrequire("simple-statistics")keep working unchanged — only the internal CJS bundle path moved. (Code that hard-coded the deep pathsimple-statistics/dist/simple-statistics.js, bypassing the package entry points, should switch to the package name or the.cjspath.)
v7.9.2
Patch Changes
-
d571a60: Fix quantile() bug when an array was provided as the second argument
Thanks Alexander Kireyev for the identification
and fix.
v7.9.1
Patch Changes
- 9c1bb2f: fix: gamma() no longer infinitely recurses for 0 < n < 1
v7.9.0
Minor Changes
- b7b2053: Add weighted mean, weighted variance, weighted standard deviation, and weighted quantile.
v7.8.9
Patch Changes
- 2daf714: Adopt changesets as a release mechanism
- 8bb4ae7: Quantiles were incorrect when they were interpolating between two elements in the input. They now match type=7, which is the default in numpy.percentile and R's quantile.
All notable changes to this project will be documented in this file. See standard-version for commit guidelines.