Regression — build 2026-11-02.64
This build fixes the problems found by an audit of Tests ▾ → Regression (linear, logistic, ordinal logistic and Poisson). It also fixes the problems found in the build .63 review of the t-tests, the correlation matrix and multiple imputation.
What was wrong, and what changed
Numbers
-
Collinear predictors. The same variable in other units (pesos and thousands, monthly and yearly, an affine timestamp) is now an error that names the variable:
predictors are collinear: “inc_k” is a combination of the other predictors …
Before, it was caught or missed depending on the units. When missed, the page showed impossible or believable but wrong results: R² = −21.9 or 1.000, a negative F, or “significant” coefficients. A predictor that does not vary, or a category with no rows in the sample, is also named.
- Linear regression is now solved by Householder QR, the method R’s
lmuses (lsqQRinsrc/app/engine.mjs).- Before, it built X′X from raw sums and inverted it with an absolute tolerance.
- Rows are folded into a small triangle block by block, so memory stays small for very large files.
- Collinearity uses R’s unit-free rule: a column with less than 10⁻⁷ of its length left, after the columns before it, is dropped.
- The residual sum of squares comes from the residuals themselves, and the total sum of squares from centered values, so R² stays between 0 and 1.
- NIST StRD accuracy:
- Longley: coefficients to 14–15 digits, standard errors to 12.7 (before: 4 digits; 84.893 shown for 84.915).
- Wampler 1 and 2: 10–14 digits.
- Logistic and Poisson (IRLS) solve each step with the same QR, and convergence no longer depends on units. With
income in pesos and a variable of about 10⁻⁶, they match R’s
glmto 8 digits, classical and robust. - Ordinal logit now:
- fits on centered, standardized predictors and transforms the estimates and their covariance back exactly;
- uses exact (analytic) second derivatives instead of numerical ones;
- flags separation by the size of a coefficient’s effect over the predictor’s range, not by the raw coefficient (which depends on units).
Before:
- income ≈ 300,000 or 1,000,000 did not converge, and every coefficient was 0;
- timestamps gave the wrong sign;
- income ≈ 100,000 had standard errors 5–10% off;
- a rate ≈ 0.001 raised a false “did not converge / perfect separation” warning.
All of these now match R’s
MASS::polr. - Model F (robust, clustered or survey) is computed on the correlation scale, so tiny coefficients no longer make it “—”.
- Margins (predicted values) use the model’s own variance: robust, clustered or survey. Before, they always used the classical one, so the bands were too narrow.
Code and Stata behaviour
- Yes/no outcomes.
- The value modeled as 1 is now 1 for 0/1 data, otherwise the higher code (2 for 1/2) or the second value in
sorted order (“sí” for “no”/”sí”). That is what R’s
factor()and a Stata recode give. Before, it was whichever value was rarer. - The exported code recodes first:
- Stata:
generate byte esi_1 = (esi == "sí") if !missing(esi), thenlogit esi_1 …. - R:
glm(I(esi == "sí") ~ …, family = binomial).
- Stata:
- Before, both failed: R said “y values must be 0 <= y <= 1”, and Stata’s logit needs 0/1.
- The value modeled as 1 is now 1 for 0/1 data, otherwise the higher code (2 for 1/2) or the second value in
sorted order (“sí” for “no”/”sí”). That is what R’s
- Weights follow Stata.
- In the console:
[pw=](or[pweight=]) means robust standard errors, as in Stata, so the page matches Stata (before, it was 12% smaller).[aw=]/[aweight=]gives ordinary standard errors inregress.[iw=]does the same inlogit,poissonandologit.- Weight types Stata would refuse are refused, with the reason:
[aw=]with logit,[fw=], and[iw=]with regress.
- On the page, the logged command names the weight type that matches what was computed:
[aw=]/[iw=]with ordinary SEs, and[pw=]with robust, clustered or survey SEs. A note under the variance choice says so.
- In the console:
- Robust R code for logit, Poisson and ordinal logit uses
vcovCL(m, type = "HC0"), which is Stata’s n/(n−1). Linear regression keepsvcovHC(m, type = "HC1").
Display and wording
- Small coefficients keep three significant digits: 0.0000396 (0.00000291) instead of 0.000 (0.000). Odds and rate ratios near 1 keep their digits: 1.0000108.
- The interpretation describes a tiny +1 step per a meaningful one: inc (OR 1.26 per +10,000 — each +10,000 multiplies the odds by 1.26×).
- Categories are compared with the reference category: grupo = C (OR 9.55 — the odds are 9.55× those of grupo = A). Before, it said “each +1 multiplies…”.
- Interactions.
- A main effect is described as holding where the other variable is at its reference (x2 … when sexo = Hombre).
- The interaction term is how much that effect changes (how much the effect of x2 changes when sexo = Mujer).
- Standardized β is not used to rank terms there.
- Stars: one convention on every page, set in Settings → Stars.
- The default is
* p < .05, ** p < .01, *** p < .001, so a star always means significant at the usual .05. - The other choice is
* p < .10, ** p < .05, *** p < .01. - Before, regression used .10/.05/.01 and the correlation matrix used .05/.01/.001.
- The default is
From the build .63 review
- t-tests.
- After ⇄ swap, or with groups picked from higher code to lower, a one-sided test now exports the R alternative in
R’s own order: “first > second” on the page is
alternative = "less"in R. - The console refuses unknown ttest options, as Stata does (
ttest y, by(g) foo(3)).
- After ⇄ swap, or with groups picked from higher code to lower, a one-sided test now exports the R alternative in
R’s own order: “first > second” on the page is
- Correlation matrix.
- With a weight, the R code computes the weighted correlation (
cov.wt, on the values or on the ranks). - Stata’s
spearman, which takes no weights, is replaced by the equivalent ranks pluspwcorr … [aw=]. - The default variables keep continuous measures whose values never repeat (height, income); only whole-number identifiers are left out.
- In capitals, “SPEARMAN ρ” read as “SPEARMAN P”; it is now “SPEARMAN RHO”.
- With a weight, the R code computes the weighted correlation (
- Plots panel. When a plot’s picture stays the same but the command changes (the selected pair stays while the matrix’s variables change), the plot card now shows the current command.
- Multiple imputation, Stata code.
- A two-category variable that is not 0/1 (text, or 1/2) becomes 0/1 before
(logit)andlogit. encodenow has its comma:encode x, generate(x_c). Without it, Stata would refuse the command. This also applies to the other Tests ▾ analyses.
- A two-category variable that is not 0/1 (text, or 1/2) becomes 0/1 before
- Means near 10⁹ are refined with a second pass, so a t-test or summary of values like 1,000,000,000.37 is exact to the last digit.
Tests
tests/regression-numerics.test.mjs runs with every node --test and needs neither R nor Python. It checks:
- the NIST StRD values (Longley, Wampler 1 and 2);
-
agreement with R on
tests/data/regression-numerics.csv. The references are intests/data/regression-numerics-reference.json, regenerated with:python3 calculator/tests/regression-numerics-data.py Rscript calculator/tests/regression-numerics-reference.RRobust and clustered variances in the R script are written out with Stata’s formulas, so no extra package is needed. It covers:
- OLS, linear in pesos and in thousands, collinear pairs, and a nearly collinear pair;
[pw=],[aw=]and clustered SEs;- logit and Poisson, classical and robust;
- ordinal logit in pesos, ×3, ×10, timestamps and a rate;
- margins with robust and classical variance;
- weighted Pearson and Spearman;
- the one-sided Welch test;
- the page’s wording, display, stars, exported Stata and R code, and console weight rules.
The exported R code was also run in R 4.3.3. The yes/no recodes give the 0/1 coefficients, and the weighted correlation code gives the page’s r and ρ.
