milescranmer/pysr/pysr
- community
Checking that the SKILL.md file is still in the repository.
Use when fitting equations to data with PySR or SymbolicRegression.jl, when a user wants an interpretable formula, symbolic model, scaling law, or empirical relation discovered from numeric data, or when debugging a PySR search that is slow, stuck, or giving poor equations.
Install
npx vskill@latest install milescranmer/pysr/pysrSKILL.md
Using PySR Effectively
PySR evolves expression trees through the Julia backend SymbolicRegression.jl, returning readable equations on an accuracy/complexity Pareto front. This guide distills the documentation and several hundred real user threads. Full docs: https://pysr.ai/
Quick start
model.equations_ is a pandas DataFrame containing complexity, loss, score, equation, sympy_format, lambda_format. Select any front row by index in predict, sympy, latex, jax, pytorch; without an index, methods use the auto-selected equation. Indexing lets you inspect and export a specific Pareto candidate instead of only the default row.
Keep the process alive
The first .fit() pays Julia startup/JIT, roughly 1-2 minutes; subsequent same-process fits start almost instantly. Repeated fresh processes repay startup and compilation for every experiment, a common agent failure.
- Keep a long-lived IPython/Jupyter kernel or REPL. New
PySRRegressorinstances are cheap; Julia runtime state lives per-process. - Scripts work. Iterate parameters inside one process instead of repeatedly relaunching
python script.py. Process reuse is an optimization rather than a requirement. - Reuse an environment containing
pysr; fresh environments re-resolve and precompile Julia packages. - Expect “Compiling Julia backend...” initially. Avoid treating normal compilation as a hang.
Candidate equations with guesses
Inject knowledge through modifiable/discardable guesses or mandatory template structure. Combine both using component/parameter guesses. Constructor strings require Julia syntax, input variable names, and enabled operators:
Single output: candidate list. Multiple outputs: lists in target-column order, guesses=[["x0 + x1"], ["x0 * x1"]]. Templates: dictionaries keyed by component/parameter names; #1, #2, etc. identify component arguments.
Guesses enter populations throughout search. should_optimize_constants=True optimizes constants/template parameters before insertion. fraction_replaced_guesses, default 0.001, controls the cycle-end replacement fraction.
Guesses are pushed into the hall of fame before generation one. Inspect accepted seeds at their complexity in model.equations_ or immediate hall_of_fame.csv; confirm insertion and optimized constants. Oversize seeds produce only Julia warning Guess expression '...' has complexity 23 > maxsize (10), using default x1, x2, ... names regardless of supplied names. They remain unrecorded but still migrate; descendants become recordable after mutations satisfy maxsize. Violations of constraints, nested_constraints, or maxdepth disappear silently. Lower-loss candidates replace seeds at the same complexity: only one expression survives per complexity.
Keep constraints compatible and set maxsize slightly above the largest seed; use the warning's complexity. Cost rises steeply, PySR warns above 40, and several-times-seed sizes can exhaust the budget without completing one generation despite appearing alive. Use warmup_maxsize_by against early bloat.
Set guesses on the estimator, never .fit(). Continue with model.set_params(guesses=[...], warm_start=True), replacing guesses while keeping data representation/search space fixed.
Recommended workflow
- Subsample: usually 1,000-5,000 representative rows suffice even from millions. Many features, heavy noise, or rare regimes benefit from more. PySR 2.0 automatically batches larger datasets;
batching=Falseforces full-data search evaluations. Batching still reevaluates hall-of-fame candidates fully. Fewer rows proportionally accelerate search. - Minimize operators: select domain-plausible operators. Redundant
pow/square/cubeor-/negenlarge search. Polynomials:["+", "-", "*"], omit/and^. - Use defaults: populations, parsimony, mutation weights, and
ncycles_per_iterationwere tuned by large-scale search in 2024-2025. Avoid older forum/paper recipes. - Debug briefly: check operators, loss, and sensible equations in a few-minute run before one long search.
- Budget the final run: evolution lacks conventional convergence and can jump families after hours. Set large
niterations; control wall-clock withtimeout_in_seconds, total evaluations withmax_evals, or stopping withearly_stop_condition="stop_if(loss, complexity) = loss < 1e-6 && complexity < 10"(Julia(loss, complexity)function).max_evalssupports compute-matched comparisons;niterations * populations * population_sizedoes not count evaluations. Monitor partialoutputs/<run_id>/hall_of_fame.csv; stop gracefully withqthen Enter in IPython. - Inspect the entire front: validate candidates and report tradeoffs.
Choosing an equation
model_selection="best" maximizes score within 1.5x minimum loss; "accuracy" minimizes loss. Score is negative log-loss slope per complexity unit; a large score marks a sharp accuracy gain for little added complexity. These heuristics control default predict.
Print model.equations_; inspect sharp loss drops, held-out model.predict(X_test, index=i) when overfitting is plausible, and limits x -> 0/inf against domain expectations. Present 2-3 candidates with tradeoffs.
Losses and weights
Default: MSE.
- MAE (mean absolute error):
elementwise_loss="L1DistLoss()"works with or without weights. For unweighted data, the equivalent custom loss iselementwise_loss="my_loss(x, y) = abs(x - y)". Useful for outliers, heavy-tailed noise, or costs proportional to absolute error; targets the conditional median rather than the mean. - Uncertainty:
model.fit(X, y, weights=1/sigma**2); built-ins apply weights automatically. Custom:elementwise_loss="myloss(x, y, w) = w * abs(x - y)^2". - Wide target range: largest values dominate MSE; use log-space loss:
- Relative/percentage error: divide by target; prediction denominators reward infinite predictions. Guard near-zero targets.
- LossFunctions.jl strings work:
"HuberLoss(1.0)","LPDistLoss{3}()". - Binary classification: +1/-1 targets, margin loss
"L2MarginLoss()"; apply sigmoid yourself for probabilities. - Asymptotes/boundaries, including y -> 0 as x -> inf, exact boundary values, and known limits: add synthetic points with very large
weights, usually preferable to custom objectives. Strict enforcement: estimate limits numerically insideloss_function, add graded penalties. - Keep losses deterministic for caching and non-negative;
loss_scale="linear"permits negatives, including log-likelihoods.
elementwise_loss receives scalar (prediction, target) or (prediction, target, weight); never sum/broadcast. Whole-vector/tree objectives require loss_function.
Scaling and features
- Normalization is optional: constants sample near N(0,1), mutate multiplicatively; extreme scales slow search. Prefer natural units, avoiding nuisance constants and hidden physical meaning. Rescale visibly struggling searches.
- Roughly 10 features or fewer need no special handling.
- Tens: increase
maxsizeand rows; search selects features reasonably well, automatic batching handles volume. Requiring all 30+ features needsmaxsizewell above 100. - Above ~50: engineer domain aggregates or template decompositions. Fields/images/sequences/graphs need meaningful features rather than pixel columns, or appropriately biased neural networks followed by symbolic component distillation, arXiv:2006.11287. Fallback: gradient-boosting preselection,
select_k_features=k. - Omitted variables failed to justify complexity through accuracy; force inclusion through an absence-penalizing custom loss.
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/pysr/SKILL.md
Popularity
- Repository stars
- 3,659
- Repository forks
- 344
- 7-day trend score
- 41
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/milescranmer/pysr/pysr)