PySR 符号回归上手:如何从数据中找出一条能看的公式
【免费下载链接】PySRSymbolic Learning in Python and Julia项目地址: https://gitcode.com/GitHub_Trending/py/PySR
手里有一批实验数据,你知道背后藏着一条简洁的关系,但说不清它长什么样。这时可以试一下符号回归:让算法直接在"输入→输出"的数据里搜索出一个可读的数学表达式,而不是拟合出一堆参数。PySR 是这条路上最常用的高性能工具——Python 界面,Julia 引擎,pip 一条命令装好。
它是什么,为什么值得试
PySR 做的是符号回归:给一列输入和一列输出,它返回的是一串表达式,比如(x0 * x0) + (cos(x3) * 2.5382),而不是一张权重表。表达式能直接读、能写进论文、能导出成 SymPy / LaTeX / JAX / PyTorch 形式。
它的主接口是 scikit-learn 风格:PySRRegressor(...)配参数,model.fit(X, y)开始搜索。搜索本身交给内置的 Julia 多目标进化算法,同时在"误差"和"复杂度"两个维度上优化,所以你拿到的是一整张候补公式表,而不是单一答案。
和常见的机器学习做法对比一下:训练一个黑盒模型,你得到的是精度;用 PySR 做一次符号回归,你得到的是规律。两者不冲突——符号回归更适合"我怀疑数据背后有一条简单规律"的场景。
快速上手:PySR 安装步骤与首次运行
安装只有两条路径,任选其一:
pip install pysr # 或者:conda install -c conda-forge pysr注意:第一次import pysr时会顺带安装 Julia 依赖,这一步会明显慢一些,属于正常现象。
下面是一个最小可运行示例。数据里混了 5 个特征,真正起作用的只有两个——跑完看看它能不能找回来:
import numpy as np from pysr import PySRRegressor from matplotlib import pyplot as plt X = 2 * np.random.randn(100, 5) y = 2.5382 * np.cos(X[:, 3]) + X[:, 0] ** 2 - 0.5 model = PySRRegressor( niterations=40, # 搜索轮数,调大结果更好 binary_operators=["+", "*", "-", "/"], unary_operators=["cos", "exp"], maxsize=20, # 公式复杂度上限 ) model.fit(X, y) # 开始搜索,终端会滚动打印新公式 print(model) # 候补公式表,带 loss 和 complexity 两列 best = model.sympy() # 被选中公式的 SymPy 形式,可直接数值计算 print(best) plt.scatter(y, model.predict(X)) # 真值 vs 预测 plt.xlabel("Truth") plt.ylabel("Prediction") plt.show()你会得到一张公式表:每一行是一个候选表达式,标注了 loss(拟合误差)和 complexity(复杂度),选中项旁边有一个箭头。print(model)输出的表可以直接截图放进报告。
典型用法:三个场景对应三种做法
从物理数据反推规律
场景:粒子物理、天体物理里经常遇到这种情况——表观量来自一张查找表,但实验数据本身可能服从一条更短的公式。
做法:把测量值当X和y,用 PySR 做一次符号回归,公式的复杂度上限(maxsize)设得比预期稍大一点即可。
你会得到什么:一条比查表更短、更可外推的表达式,且可以无损导出成 LaTeX 发表。仓库文档里收录了电子负电性这类真实案例,效果见下图。
带噪声数据 + 特征选择
场景:数据里有测量噪声,而且特征列很多,真正起作用的只有几个。
做法:denoise=True会在搜索前用高斯过程把目标去噪;select_k_features=5用随机森林预筛出最多 5 列候选特征,搜索只在保留的列上进行。
你会得到什么:训练日志会打印一行Using features [...],让你知道最后用了哪些列。若数据里离群点多,把损失换成 L1(L1DistLoss(),对离群值更稳健)通常比默认 L2 效果更好。
用约束条件限定搜索空间
场景:默认搜索空间太大时,进化算法容易钻进又长又丑的死胡同,比如反复嵌套sin(cos(x))。
做法:nested_constraints可以禁止特定嵌套;maxsize、maxdepth控制公式总长度与嵌套深度;constraints限制某个算子内部子树的复杂度;还可以用 Julia 语法定义自定义算子,例如把四元最小值直接写成min4(a, b, c, d) = min(a, b, c, d),给搜索一条更短的结构路径。
注意这里:约束设得越合理,搜索越快收敛到干净的形式。官方调参建议见 docs/src/tuning.md。
新手常见坑:首次运行报错怎么办
- 第一次 import 很慢:Julia 依赖在首次导入时装。赶时间可以直接用仓库自带的 Docker 环境(Dockerfile),或提前手动装好 Julia 依赖。
- 在 Jupyter 里体验打折:进度条和"按 q 提前停止"是 IPython 的功能,笔记本里按中断只会拿到当前已有公式。建议直接开 IPython 跑搜索。
- warm_start 状态冲突:
warm_start=True会从上次搜索处继续,但若你中途改了算子或maxsize,会直接报错。先model.reset()再改参数。 - 算子给太多:
+、-、*、/、exp全开,结果往往更长更丑。只给物理上可能出现的算子,搜索会明显更快。 - 公式要验证:训练集上 loss 接近 0 不代表公式正确。务必在训练集外的数据上再跑一次
model.predict,确认误差量级。
什么时候该用,什么时候别用
符号回归最适合:特征少(个位数到十几维)、数据量在几百到几万行、背后关系相对简洁、且你确实需要"一条能看的公式"而不是更高精度。特征成百上千且关系复杂时,直接跑很难命中,先做特征选择或按官方做法拆成小块再搜。如果你的目标只是预测精度、完全不在乎可解释性,传统模型会更省事。最后一条是硬边界:找到的公式必须在独立数据上验证后再使用。
延伸资源
- 仓库入口与快速示例:README.md
- 文档目录:docs/src/,其中 getting-started.md 是最短上手路径,tuning.md 讲参数怎么调
- 可运行例子:examples/ 下有两个完整 notebook 和几十个单文件脚本(
automatic_batching.py、any_arity.py等) - 导出实现源码:pysr/,
export_sympy.py、export_latex.py、export_jax.py等对应各格式导出
【免费下载链接】PySRSymbolic Learning in Python and Julia项目地址: https://gitcode.com/GitHub_Trending/py/PySR
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考