Repository navigation
R Python differences
The Python port is a numerical port: on the same data, the two implementations are expected to return the same estimates, not merely similar ones. Both optimise with NLopt (R through nloptr, Python through nlopt) from the same starting values, and the Python densities reproduce R's.
This page records where that holds and where it does not, as measured on the versions below. Re-run the scripts after upgrading either side. What exists in only one language is on Roadmap.
| R side | Version | Python side | Version |
|---|---|---|---|
| R | 4.6.1 | CPython | 3.14.4 |
greybox |
2.0.12 | greybox |
1.0.11 |
nloptr |
2.2.1 | nlopt |
2.10.0 |
statmod |
1.5.2 | numpy |
2.5.0 |
scipy |
1.18.0 | ||
pandas |
3.0.3 | ||
rpy2 |
3.6.9 |
Platform: Linux x86-64, glibc 2.43.
Every example on the wiki pages is run in both languages, on identical data (written by R and read by Python where random numbers are involved). On those examples:
| Quantity | Measured on | Agreement |
|---|---|---|
| ALM estimates, standard errors, information criteria, prediction intervals |
ALM: mpg ~ . with dlnorm, mpg ~ wt + hp with dnorm, dlaplace, LASSO, ROLE, a custom loss; AR(1) |
Same to the printed digits (4 decimals in the summaries, 6 in the intervals) |
| Selection path and selected model |
stepwise: mtcars
|
IC path 209.1693, 166.8866, 158.2020, 156.4271, 157.9231 in both |
| Combined parameters, importance, intervals | CALM | Same to the printed digits |
| Information criteria of the candidate models | AID | 10 decimals (e.g. 307.70083267522057 in both) |
Demand types, stockouts, new, obsolete
|
AID, aidCat()
|
Identical |
| Error measures |
measures, measures()
|
All 16 identical to 4 decimals |
| Rolling-origin forecasts and holdouts | rolling_origin | Same to the printed digits |
dgamma, dnorm, dlnorm log-densities |
distributions: 2000 random arguments each | Bit-identical |
supsmu(), lowess(), with and without tied x
|
Smoothers | Bit-identical |
| STI strengths |
EDA: AirPassengers
|
0.1061, 0.8613, 0.0326 in both |
| RMCB means, intervals, p-values |
RMCB: tukey, dnorm, dlnorm, dlaplace
|
Same to 6 decimals |
| Item | Difference | See |
|---|---|---|
RMCB with a general alm()
|
The means and p-value match, but the interval widths can differ: R bootstraps the covariance matrix when the Hessian is inaccurate, Python always uses the Hessian. | RMCB |
| Random draws |
r*() functions use NumPy's / SciPy's generators, so a seed does not reproduce R's draws. Examples that need random data generate it in R. |
distributions |
| Column names of lags | Python names a lag B(x,1), R B(x, 1). |
manipulations |
The Python repository has tests that run R through rpy2 on the same inputs and compare the results. They need rpy2 and R with greybox; they are skipped otherwise.
| Test file | Covers |
|---|---|
tests/test_r_python_compare.py |
Distribution functions. |
tests/test_distributions_compare.py |
Distribution functions against the R sources of the repository. |
tests/test_alm_distributions_compare.py |
ALM across the distributions. |
tests/test_alm_parity_compare.py |
ALM estimates, counts, information criteria, losses, checks of the regressors, occurrence models. |
tests/test_residuals_compare.py |
Standardised and studentised residuals, hat values, outliers. |
tests/test_scale_compare.py |
Scale model: ALM(scale_formula=), sm(), implant(). |
tests/test_pointlik_compare.py |
point_lik(). |
tests/test_diagnostics_compare.py |
outlier_dummy(). |
tests/test_selection_compare.py |
stepwise(), CALM(), rolling_origin(). |
tests/test_measures_compare.py |
Point, interval and half-moment measures. |
tests/test_association_compare.py |
association(), pcor(), mcor(), cramer(), determination(), determ(). |
tests/test_formula_compare.py |
formula() against model.frame() / model.matrix(). |
tests/test_xreg_compare.py |
xreg_expander(), xreg_transformer(), xreg_multiplier(), temporal_dummy(). |
tests/test_stick_compare.py |
stick() and rmcb(). |
tests/test_aid_compare.py |
aid(), aid_cat(). |
tests/test_bootstrap.py |
coefbootstrap(). |
On the versions above, these files give 2093 passed:
cd python
OMP_NUM_THREADS=1 .venv/bin/python -m pytest tests/test_*compare*.py tests/test_bootstrap.py -q| Topic | R | Python |
|---|---|---|
| Model fitting | Formula interface: alm(y ~ x, data)
|
scikit-learn style: ALM().fit(X, y), with formula() building (y, X)
|
| Names |
camelCase (xregExpander) |
snake_case functions, PascalCase classes (xreg_expander, ALM); map on Home
|
| Results | lists read with $
|
objects read with .
|
| Parameters of a model |
coef() includes the intercept |
coefficients includes it; coef excludes it (scikit-learn's coef_ convention) |
| Forecasting an AR model without regressors | forecast(model, h) |
model.predict(np.ones((h, 1))) |
| Time series input |
ts objects carry the frequency |
arrays carry none: stick() requires lags, and xreg_expander() defaults to lags [-1, 0, 1]
|
rmcb() plot |
drawn unless outplot="none"
|
never drawn by rmcb(); call result.plot()
|
| Positions | 1-based | 0-based, except where a result reproduces R's positions (the stockouts of aid()) |
rolling_origin() call |
a string evaluated with data, h, counti, … |
a function of data, h and optionally counti, … |
Both languages run the same optimiser from the same starting values on the same likelihood, so a materially different optimum is not "optimiser noise". Evaluate the loss in both languages at identical parameter values: equal there means the starting values differ; different there means the two are not fitting the same model (data, regressors, distribution parameters).