| English | 日本語 |
Cover the numerical core of R’s stats package (and the related parts of base) in plain
TypeScript, with R’s function names, defaults and numerical results: distributions, descriptive
statistics, hypothesis tests, linear models, special functions, numerical methods and the basics
of linear algebra. R is the oracle: every function is tested against R’s output, and against
high-precision reference values where R itself is inaccurate (see docs/accuracy.md).
The point is to fill a gap. JavaScript has libraries for distributions and special functions
(such as stdlib-js, which is accurate and broad) and for
descriptive statistics, and R itself can run in the browser through WebAssembly (webR), at the
cost of a download of tens of megabytes. What is missing is a light library whose results can
be trusted to match R, from the distributions up to the hypothesis tests, including R’s
set.seed() random streams.
The priority is the analyses used in medical, biological and psychological research. Where R’s
stats has no function for one of them, the reference is a widely used CRAN package (such as
car, multcomp or survival), installed in the oracle image from the same dated snapshot as
the other packages.
SciPy (scipy.stats, scipy.special, scipy.linalg) is a source of ported code and a guide
to what is useful, but not a target: functions that have no counterpart in R cannot be checked
against R and are not a priority.
| Area | Status |
|---|---|
| Special functions | gamma, lgamma, beta, lbeta, choose, lchoose, factorial, lfactorial, digamma, trigamma, psigamma, besselI, besselK, besselJ, besselY, and erf, erfc, erfinv, erfcinv, gammainc, perm (not in R), and the log1p-type functions of R’s C API log1pmx, lgamma1p, log1mexp, log1pexp |
| Distributions | d/p/q with lowerTail and logP for all 20 distributions in R’s stats (including the studentized range), the non-central chi-squared, t, F and beta, and inverse gamma, Kumaraswamy, Pareto, triangular, Laplace (extraDistr) and arcsine; distSummary for 23 of them (all but the Wilcoxon signed rank and rank sum distributions and the studentized range) |
| Random numbers | R’s default Mersenne-Twister with set.seed()-compatible streams, and RNGkind with "L'Ecuyer-CMRG" (with parallel’s nextRNGStream and nextRNGSubStream) and sample.kind = "Rounding"; 26 r* functions including rmultinom (extraDistr’s streams for the extra distributions), sample, sampleInt, r2dtable |
| Descriptive statistics | R’s summaries (mean, variance, quantile with all nine types, rank, cov/cor matrices, table, cut, hist, ecdf, scale, …) and e1071’s and DescTools’ (skewness, kurtosis, geometricMean, modes, meanAD, cv) |
| Hypothesis tests | R’s htest functions: tTest, chisqTest (including simulated p-values and two factor vectors), fisherTest (including r × c and simulated p-values), wilcoxTest, corTest, binomTest, poissonTest, propTest, mcnemarTest, varTest, bartlettTest, kruskalTest, friedmanTest, quadeTest, flignerTest, moodTest, onewayTest, shapiroTest, mantelhaenTest, ansariTest (with its confidence interval), ksTest, the pairwise* helpers, pAdjust; aov (one way), TukeyHSD, zTest (BSDA), brunnerMunzelTest (lawstat) |
| Linear models | lm with a matrix interface and summary.lm’s quantities, confint, predict; glm with a matrix interface (every family and link of R’s stats), summary.glm, the four kinds of residuals, hatvalues, rstandard, cooks.distance, predict with standard errors, profile likelihood confint (exact limits) and anova; robust covariances: sandwich’s vcovHC (HC0 to HC5) and vcovCL (one-way and multi-way clustered, HC0 to HC3) and lmtest’s coeftest and coefci, for modified Poisson regression (risk ratios), weighted regression after inverse probability weighting and difference-in-differences |
| Analysis of variance | aov, lm and modelMatrix from formulas (several factors, interactions, covariates, Error() strata), anova (sequential and model comparison), car’s Anova (types II and III), afex’s aov_ez as aovEz (repeated measures, Greenhouse-Geisser and Huynh-Feldt, generalized eta squared), mauchly.test |
| Effect sizes and power | effectsize’s cohens_d, hedges_g, eta_squared, omega_squared, epsilon_squared (from anova and Anova tables, exact confidence limits); power.t.test, power.prop.test, power.anova.test and the power functions of pwr |
| More tests | leveneTest (car), propTrendTest (prop.trend.test), jonckheereTest (DescTools and clinfun), cochranQTest (DescTools), adTest, lillieTest, cvmTest, sfTest, pearsonTest (nortest); tTOST and tsumTOST (TOSTER: equivalence and minimal-effect t tests for one, two and paired samples, with the standardised mean difference) |
| Contingency tables and proportions | binomCI, binomDiffCI, binomRatioCI (DescTools’ BinomCI, BinomDiffCI, BinomRatioCI), oddsRatio (epitools, and epiR’s score interval), fisherTest(x, { midp: true }) (exact2x2), boschlooTest (Exact), gTest, stuartMaxwellTest, goodmanKruskalGamma (DescTools), lblTest (coin), chisqTest(x, { nMinus1: true }) (Campbell’s ‘N − 1’ test) and Freeman-Tukey residuals, tost (equivalence), binomDiffEquivalenceTest (score TOST of two proportions) |
| Multiple comparisons | PMCMRplus’s dscfAllPairsTest (Steel-Dwass), kwAllPairsDunnTest, kwManyOneDunnTest, manyOneUTest (Steel’s many-one rank test), dunnettTest, gamesHowellTest, tukeyTest; dunnTest (dunn.test); glhtDunnett (multcomp); Dunnett-type probabilities computed exactly (R’s are randomised) |
| Mixed models | lme4’s lmer as lmer (REML and ML; correlated and uncorrelated random effects (x \| g), (x \|\| g), crossed and nested grouping factors a/b, a:b), with the quantities of fixef, vcov, coef(summary()) (without p-values), VarCorr, ranef, fitted, residuals, logLik, AIC, BIC, deviance, REMLcrit and isSingular; lmerTest’s Satterthwaite t- and F-tests (summary, contest, Type I/II/III anova) and lme4’s anova of several fits; lme4’s glmer as glmer (all glm families, Laplace approximation and adaptive Gauss-Hermite quadrature) with summary, anova and predict (glmerSummary, glmerAnova, glmerPredict) and predict of lmer (lmerPredict); implemented from Bates et al. (2015) with a sparse Cholesky factorisation; the estimates are the exact optimum of the criterion (lme4 stops close to it). In its own area @numero-uno-jpn/rstats/mixed (dist/mixed.js), not in the single-file bundle |
| Survival analysis | survdiff (log-rank and the G-rho family) and survfit (Kaplan-Meier with log, plain and log-log intervals and the median) and coxph (Cox regression: Efron and Breslow ties, weights, strata, the summary tests, the robust variance and cluster) of the survival package |
| Diagnostic accuracy and method comparison | pROC’s roc, auc (with the partial AUC), ci.auc, roc.test and coords (DeLong’s interval and tests, the bootstrap on R’s random stream); epiR’s epi.tests as diagnosticTests; BlandAltmanLeh’s bland.altman.stats as blandAltman (with the exact interval of the limits of agreement); mcr’s mcreg (Deming, weighted Deming and Passing-Bablok regression with analytical, jackknife and bootstrap intervals) |
| Agreement and reliability | kappa2, kappamFleiss, icc (irr), ICC (psych’s six forms of Shrout and Fleiss), cronbachAlpha, partialR (psych), polychor, polyserial (polycor, two-step and maximum likelihood), pbvnorm, omega (McDonald’s ω, psych); effect sizes of repeated-measures designs (Error() strata and aovEz) |
| Optimisation | factanal (maximum likelihood, varimax and promax); optim with all six methods (Nelder-Mead, BFGS, CG, L-BFGS-B, SANN, Brent), following R’s iterations (except CG, which tries the minimum of the parabola where R tries the midpoint, so its path differs), and optimHess |
| Data handling | completeCases (complete.cases), naOmit (na.omit), subset, merge, rbind and cbind of data frames, tapply, split, aggregate, pivotLonger and pivotWider (tidyr); formula forms of the tests (tTest("y ~ g", data), kruskalTest, friedmanTest("y ~ w \| b", data), corTest("~ x + y", data), …) |
| Linear algebra | the matrix functions of R’s base, with Matrix::lu, prcomp (stats) and MASS::ginv: matrix arithmetic, crossprod, norm, backsolve, chol, qr (R’s pivoting and LAPACK), solve, det, rcond, kappa, svd, eigen (symmetric and general), lu, prcomp, ginv, schur (Matrix::Schur) and expm (expm’s Higham08, Padé and Taylor methods) |
| Numerical methods | integrate, optimize, uniroot, approx, spline/splinefun/splinefunH, Lagrange (pracma) and Hermite interpolation, fixed-step ode (deSolve), grad/jacobian/hessian (numDeriv) |
| jStat | every jStat function has a replacement (docs/migrating-from-jstat.md), checked against jStat |
The full list is in the README; known differences from R are in docs/differences-from-r.md.
The priority is that a medical or psychological study can use the right method: exact methods for small samples, and effect measures with their confidence intervals, not only p-values. The list was drawn up against the methods of a statistics web application for medical and psychological research (2026-11-06). In order of priority; the R function or package that each item is checked against is given in brackets.
survfit’s cumulative hazard]; the restricted mean
survival time [survRM2]; the test of proportional hazards [cox.zph]; time-dependent covariates in the (start,
stop] form [coxph]; competing risks: cumulative incidence, Gray’s test and Fine-Gray regression [cmprsk];
accelerated failure time and Tobit models [survreg].ph2simon]; the reference for each is chosen when the item is taken up.confint (profile likelihood) and simulate of lmer and glmer fits [lme4]. The
mixed area stays out of the root export and the single-file bundle dist/rstats.js (decided 2026-11-05); adding
it later would not break compatibility.polr], nonlinear regression [nls and the
self-starting models], robust and quantile regression [MASS rlm, quantreg], GEE [geepack]; MANOVA [manova],
discriminant analysis [MASS lda], canonical correlation [cancor]; cluster analysis [hclust, kmeans];
multidimensional scaling and correspondence analysis [cmdscale, MASS isoMDS, ca]; Tamhane’s T2 and Page’s
test [PMCMRplus], Grubbs’ test [outliers]; regularised regression [glmnet]; time series [acf, arima].The former items 1 (robust standard errors) and 2 (diagnostic accuracy and agreement of measurements) were done in
1.3.0. Left out of them, as recorded in the “rStats.js’s choices” of their behaviour documents
(oracle/robust-behaviour.md, oracle/roc-behaviour.md,
oracle/methodcomparison-behaviour.md): the score and dfbeta residuals of
coxph (computed for the robust variance, not exported); pROC’s Venkatraman test, intervals of the partial AUC,
smoothed curves, percent, the intervals of coordinates, thresholds, sensitivities and specificities (ci.coords,
ci.thresholds, ci.se, ci.sp), power.roc.test and multiclass curves; intervals of Youden’s index and of the
number needed to diagnose; Bland-Altman’s regression-based limits and limits for repeated measurements [SimplyAgree
would be the reference], and one-sided limits; mcr’s PaBaLarge (the binned Passing-Bablok for large data),
LinReg, WLinReg, PBequi and TS; ICC with missing ratings; TOSTER’s log_TOST, wilcox_TOST,
boot_t_TOST and power functions (the power belongs to item 2).
Speed: done for now. The incomplete beta function with both parameters large uses Temme’s uniform asymptotic
expansion (constant time instead of a continued fraction of length √(a + b)), with one parameter large and the other
small DiDonato and Morris’s expansion (pt and pf with large degrees of freedom, pbeta(x, 1e6, 10), pbinom
with x near 0 or n: about the time of a typical pbeta instead of up to 30 times more), and the main d/p functions
leave out the double-double steps that an error bound shows to be unnecessary (see
docs/performance.md). Remaining: the continued fraction, which stays in double-double and is
still used where neither expansion applies (moderate parameters, such as a = 30 and b = 20, where it is short, and
the far tails).
Out of scope: the parts of SciPy with no counterpart in R (most of scipy.special and the
distributions that only scipy.stats has). Structural equation models (lavaan, including confirmatory factor
analysis and multilevel SEM) are out of scope too: they are the size of a library of their own; for the same reason
so are item response theory [mirt, ltm], latent class analysis [poLCA], multiple imputation [mice] and Gaussian
mixture models [mclust]. Also out of scope:
recycling distribution parameters as vectors (rnorm(3, mean = c(0, 10, 100))), since map does
the same with R’s results and random stream (see
docs/differences-from-r.md). The other RNG kinds (Wichmann-Hill, Marsaglia-Multicarry, Super-Duper, Knuth-TAOCP) and normal kinds
(Kinderman-Ramberg, Ahrens-Dieter, Box-Muller) are out of scope too: they serve only to reproduce
old code.
Users of a bundler only get the functions they import (pnorm alone is 1.6 KB gzipped), so
adding functions costs them nothing. For CDN use there is one file per area
(dist/distributions.js, dist/tests.js, dist/linalg.js, dist/descriptive.js,
dist/numerics.js, dist/special.js, dist/mixed.js), built with esbuild’s code splitting so that shared code is
not duplicated, and dist/rstats.js with everything except mixed (the mixed models are large, so they stay out
of the single-file bundle; decided 2026-11-05). The same areas are subpath exports of the
package (@numero-uno-jpn/rstats/linalg, …). npm run size reports the sizes. After
publishing to npm, CDNs that bundle per export (such as esm.sh with ?exports=) are a further
option.