PySR
Multi-population evolutionary search returning a complexity/error Pareto front.
Usage
import kd
dataset = kd.load_burgers()
model = kd.Model(algorithm="pysr")
model.fit(dataset)
print(model.best_expr_)
Main parameters
| Parameter | Default | Resume | Description |
|---|---|---|---|
niterations |
40 |
resume-safe | PySR's internal GP iterations per fit; the facade generations parameter maps here, and on a resume it is the number of further iterations the new segment runs from the archived populations. |
population_size |
33 |
init-only | Members per PySR population. |
populations |
15 |
init-only | Number of PySR populations. |
maxsize |
20 |
init-only | Maximum generated expression size. |
All fields of PySRConfig
| Field | Type | Default |
|---|---|---|
terms |
tuple[str, ...] |
('u', 'u_x', 'u_xx', 'mul(u, u_x)') |
seed |
int |
0 |
niterations |
int |
40 |
population_size |
int |
33 |
populations |
int |
15 |
maxsize |
int |
20 |
binary_operators |
tuple[str, ...] |
('+', '-', '*', '/') |
unary_operators |
tuple[str, ...] |
('sin', 'cos', 'exp', 'log') |
extra_pysr_kwargs |
dict[str, Any] \| None |
None |
The KD wrapper
PySR is a third-party package, installed separately, and its authors document the search itself. The points below are specific to driving it from KD.
One fit per run. PySR performs one batch search and returns its whole
hall of fame, so a KD run has a single iteration rather than a curve across
generations. A resumed run (resume_from) continues that search from the
populations and hall of fame stored in the checkpoint; the resuming model's
generations is the number of further PySR iterations the new segment runs.
On a PDE dataset it regresses over KD's term library. PySRConfig.terms is
the set of candidate term columns handed to PySR, in KD's function-call
notation. The constants PySR fits are stripped off, leaving the structural
terms for KD to refit.
On a table it keeps the expression whole. Hand fit() a
kd.TabularDataset and KD runs PySR in its tabular mode: the columns are the
feature columns of the table, so terms comes from the dataset rather than
from the configuration, and the expression PySR returns is kept intact, fitted
constants and all.
The operators are configurable in either mode. binary_operators and
unary_operators define the operators PySR may combine its columns with, and
both are read from the configuration regardless of which kind of dataset it was
handed.
best_score_ is computed by KD. PySR's own loss is not returned. The
selected expression is refitted by least squares on the data of that run, and
the NMSE of that refit is the score, where lower is better. On a table
that refit is a single outer coefficient, so the score measures the shape of the
expression rather than the expression as written. The refit
coefficients arrive on result_.final_eval.coefficients, and on
result_.equation alongside the terms they belong to; best_expr_ itself is
the structural expression on a PDE dataset, and PySR's own expression,
constants included, on a table.
The full front is returned with the result. Every hall-of-fame entry that
converts to KD's notation is kept, and model.result_.pareto_front() returns
them as typed entries: the expression in KD notation, PySR's own two axes as
complexity and loss, and on a tabular run the outer coefficient fitted for
that entry as scale. The series behind them stay on model.result_.recorder
under the same names, pareto_nmse among them, which is KD's independent
re-score of each entry.
Anything else PySR accepts goes through extra_pysr_kwargs, unchanged.
References
Cranmer (2023). "Interpretable machine learning for science with PySR and SymbolicRegression.jl". arXiv:2305.01582. Paper
Documentation: ai.damtp.cam.ac.uk/pysr
Code: MilesCranmer/PySR