Skip to content

Avoid recompiling the term walk for every table type - #355

Open
matthieugomez wants to merge 1 commit into
JuliaStats:masterfrom
matthieugomez:nospecialize-data
Open

Avoid recompiling the term walk for every table type#355
matthieugomez wants to merge 1 commit into
JuliaStats:masterfrom
matthieugomez:nospecialize-data

Conversation

@matthieugomez

@matthieugomez matthieugomez commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Calling modelmatrix or ModelFrame on a table with a different set of columns (or column types) than before costs ~0.1-0.2s of compilation, even if the formula has already been used.

Two reasons:

  1. columntable turns the data into a NamedTuple, whose type encodes the column names and types. This PR adds @nospecialize to the data argument of methods using the data.
  2. @nospecialize is not enough on its own, because the term walk uses comprehensions and broadcasts like [modelcols(tt, d) for tt in t.terms] or modelcols.(ts, Ref(d)). The closure captures d, so its type includes the NamedTuple type of the table, and everything downstream is re-inferred anyway. This PR replaces them by loops (_modelcols_each).

Nothing changes in the API or in the returned values. Callers do lose return-type inference through modelcols/modelmatrix; I checked that GLM, MixedModels, StandardizedPredictors, RegressionFormulae, Econometrics and FixedEffectModels don't rely on it in their tests.

Timings (first call on a new table type, formula y ~ 1 + a + b + c + e + a&b already used once, Julia 1.12):

master this PR
modelmatrix(f, d), one extra unused column 0.179 s 0.022 s
modelmatrix(f, d), log(a) in the formula, one extra column 0.092 s 0.003 s
ModelFrame(f, d) + modelmatrix(mf), one extra column 0.094 s 0.011 s
ModelFrame(f, d) + modelmatrix(mf), two extra columns 0.120 s 0.018 s

Orthogonal to #354, which deals with the per-formula cost.

- @nospecialize the data argument of modelcols, schema, concrete_term, checkcol, missing_omit, ModelFrame, modelmatrix, response
- Replace comprehensions, generators and broadcasts over the data with loops so no closure captures the table type
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant