SISSO从入门到实践:自动挖掘物理描述符的完整指南

发布时间:2026/10/22 15:50:10
SISSO从入门到实践:自动挖掘物理描述符的完整指南
1. 项目概述做材料计算和机器学习交叉研究的朋友十有八九都遇到过一个问题特征太多样本太少。你吭哧吭哧从晶体结构里算了几十个、上百个特征比如带隙、形成能、原子半径、电负性、体积模量之类的想拿它们去预测某个目标性质。结果一看样本才几十个常规的机器学习模型要么过拟合要么完全没法解释。你要的是能看懂、能复现、能写成公式的东西不是黑箱。这时候SISSO就派上用场了。SISSO的全称是Sure Independence Screening and Sparsifying Operator直译过来是“确定独立筛选与稀疏化算子”。这名字听起来拗口但你把它当成一个“从海量特征组合中自动找出最简单且最准的公式”的工具就对了。它做两件事第一用筛选策略把特征空间暴力缩小第二用稀疏回归从缩小的空间里挑出几个关键特征组合成描述符。最终输出的是一个带物理意义的解析公式比如“目标性质 系数1 × 特征A 系数2 × 特征B”这个公式是你能直接写进论文里的那种不是一颗黑箱树。SISSO目前在材料信息学领域非常流行特别是用于预测材料的带隙、形成能、弹性模量、催化活性等。但它的适用范围不止于此任何你能把研究对象抽象成“特征矩阵 目标向量”的问题理论上都能用。这篇博文我会从安装到使用走一遍完整流程把我在实际踩坑中总结的经验一并分享出来适合做计算材料、化学信息学、物理建模的研究生和科研从业者也适合想给自己数据建模增加一个解释性工具的工程师。如果你之前只跑过随机森林或神经网络这次可以换个口味看看怎么用一个“小而美”的模型把物理解释清楚。2. 核心思想解密2.1 SISSO到底在解什么问题咱们先理清一个概念。传统机器学习做回归比如你用随机森林它输出的是预测值但你看不到规则不知道模型内部用哪些特征、怎么组合。SISSO的目标不是“预测得准”而是“找到一个公式既能预测得准又具有物理意义”。这本质上是一个符号回归问题面对的是特征空间中的组合爆炸。举个实际例子你想预测某种钙钛矿材料的形成能。你手头可能有30个基础特征离子半径、电负性、价电子数、晶格常数、容差因子等等。如果只允许你用两个特征做一次幂的线性组合那组合空间就是30选2再考虑加法、减法、乘法、除法组合数量会上到几千。但如果你用三个特征做非线性组合允许平方、立方、倒数、指数、对数等运算那组合空间就爆炸了——10的12次方量级根本不是暴力枚举能解决的问题。SISSO分两步破解这个组合爆炸。第一步叫Sure Independence ScreeningSIS部分它不追求“最优组合”而是用一个非常廉价的指标比如每个特征和目标的皮尔逊相关系数绝对值在超大特征空间里快速过滤保留前几名的特征子集。第二步叫Sparsifying OperatorSO部分把筛好的特征子集和预设的算子库组合起来生成一堆候选特征再用稀疏回归比如Lasso或L0范数约束从这些候选中挑出最稀疏、最准的一组解。这一过程的好处是每一步都尽量“省着算”先用便宜的筛选砍掉大部分无关特征再在剩下的小空间里做精细搜索而不是一开始就硬刚。这就像你找房子先在房价数据库里筛出房价合理、面积合适的几个小区再亲自去看每个小区的户型而不是把整个城市每栋楼都跑一遍。2.2 特征空间与算子库的设计SISSO中一个特别关键的设计是“算子库”英文叫operator set。它会把你指定的基础特征当做初始特征然后通过一元和二元运算生成新的特征。常见的一元运算包括平方^2、立方^3、倒数1/x、平方根sqrt(x)、对数ln(x)、指数exp(x)等二元运算包括加、减、乘、除。通过一次算子运算从基础特征里生成一级特征再对一级特征做同样的运算生成二级特征以此类推形成特征树。这个“迭代次数”在SISSO参数里叫nsis通常设为1到3。为什么不能无限大因为迭代次数一多特征维度会呈指数级爆炸。我实测过基础特征30个算子库用最基础的加减乘除和平方、倒数迭代3次之后候选特征维度超过了10的7次方。内存不够直接崩。所以通常nsis设2就够用了如果特征空间原本就不复杂1也行。更复杂的组合也不能给你带来什么物理上的新鲜感反而容易过拟合。特征空间的维数除了受迭代次数影响还跟算子库有关。如果你加了指数、对数这种非线性很强的算子特征空间会变得非常混乱给筛选和稀疏化都增加困难。我的建议是用一组能表达你目标性质“可能具有物理形式”的算子。比如你预测形成能那可能跟体积的倒数、电负性差有关你就可以保留倒数、平方、加减乘除。如果你预测带隙可能需要更多的非线性形式如指数、对数。不是说越多越好而是越贴合物理越好。2.3 SISSO与Lasso的异同很多人问SISSO和Lasso不就是一回事吗Lasso也能从一堆特征里选出一批非零系数而且有高效的坐标系下降算法。区别在于Lasso是对“特征本身”做稀疏选择只会在原始特征列里挑几个不会自动生成“密度差除以半径平方”这种新特征。而SISSO把“生成特征”和“稀疏选择”结合在一个框架里它搜索的空间是原始特征的表达式组合所以找出来的模型往往更有解释力。而且SISSO在稀疏化时用的不是L1范数而是L0范数约束。L0范数就是“非零元素的个数”也就是显式限制描述符中最多有多少项。Lasso的L1是L0的松弛近似容易把系数收缩得太小选出的变量也受正则化强度影响。SISSO里可以直接指定描述符维度dimension比如dimension2那就强制输出一个包含两个特征的描述符公式像“性质 c1 * f1 c2 * f2”简单明了。这样确定的模型没有额外惩罚解释起来也更干净。当然Lasso在纯预测任务里仍有优势因为它速度快、稳定、容易调参。但如果你是做“描述符挖掘”想要发现新的物理规律SISSO就是这个领域的主角。3. 安装与环境准备3.1 获取SISSO源码SISSO是纯C写的命令行程序源码在项目官网上公开发布。你需要登录官网注册一个账号下载源码压缩包。也有的课题组把源码托管在代码托管平台上可以直接用git拉取。不管哪种方式拿到手是一个包含多个源文件和Makefile的目录。下载前确认你的系统是Linux或者Windows的WSL环境。SISSO在Windows原生下编译比较麻烦建议直接用Linux服务器或Ubuntu子系统。MacOS也支持编译但有些编译器参数要自己调一下。我自己的主力环境是Ubuntu 20.04这类的系统配合g编译器基本零障碍。目录里常见的文件包括sisso.cpp —— 主程序源码libfdr.cpp / libfdr.hpp —— 数据读取库functions.cpp / functions.hpp —— 特征运算实现Makefile —— 编译脚本README.md —— 使用说明SISSO.in 模板、train.dat 示例3.2 编译要点与常见报错编译前先确认系统装了g和make没装的话先补上。sudo apt update sudo apt install g make进入源码目录cd sisso make clean make如果一切顺利目录里会生成一个叫sisso的可执行文件。你可以先跑一个自带的示例验证一下。这里有个容易踩的坑很多新版本SISSO依赖Intel MKL或者OpenBLAS做矩阵运算。编译时如果你没有装这些数学库链接阶段会报错提示找不到cblas_*之类的符号。解决方法是先安装OpenBLASsudo apt install libopenblas-dev然后在Makefile里加入-lopenblas链接选项。如果你用的是Intel编译器改成-lmkl_rt之类的路径。具体看Makefile注释。另一个常见报错是fatal error: mkl.h: No such file or directory。这个说明Makefile默认用了MKL头文件但你系统没有。最简单粗暴的办法是把Makefile里的MKL相关路径注释掉改成用OpenBLAS或者你干脆改用系统自带的BLAS库。实在不行去Intel官网装个免费的MKL也可以但我觉得为跑SISSO单独装MKL有点重。编译通过后先用自带的示例数据跑一遍确认环境没问题再处理自己的数据。3.3 运行前必须理解的关键参数SISSO运行时需要两个输入文件一个描述特征和任务的文件通常叫SISSO.in另一个存放特征矩阵和目标值通常叫train.dat。此外还需要一个可选的属性字典默认叫prop.dat用于描述每个特征的物理含义。实际使用中prop.dat不是必需的但强烈建议配置因为输出结果里会带出可读的特征名方便写论文。SISSO.in是参数配置文件里面以行格式指定各类参数。常用的参数块如下1. task type (1: regression, 2: classification) 2. Y property: 目标列编号 3. nrestart: 重启次数 4. nsis: 特征迭代次数 5. dimension: 描述符维度 6. operators: 算子列表 7. ... 其他设置具体格式在不同版本里略有差异但你打开示例文件就能明白。我的经验是先按示例默认跑一遍再逐步改参数。4. 从零开始构建输入数据4.1 准备train.dat特征矩阵train.dat的格式是每一行为一个样本前几列是特征值最后一列或单独一行是指定目标值实际上不同版本对目标列位置定义不同一般SISSO.in里指定Yproperty那一列作为目标。比较常见的格式是前若干列是特征中间某列是目标最后一列是样本权重如果不考虑权重可以在参数里关闭。我建议的格式是每行样本第一列样本ID字符串可省略中间所有特征列都是浮点数最后一列是目标值。如果你是回归任务只需要浮点数。用制表符或空格分隔都行。SISSO对列数没有硬限制但特征太多会对内存产生压力。特别提醒特征列必须都是数值且不能有缺失值。SISSO没有内置缺失值处理一旦有NaN跑出来的结果全部是NaN而且不报错非常坑。所以预处理数据时删除或填充缺失值是必须的。4.2 配置prop.dat属性说明prop.dat每行列出一个属性名按顺序对应train.dat里的每一列。比如id r_m X E_form这样SISSO输出描述符时就会显示特征的原始名称而不是“col_1”。我见过很多人偷懒不写prop.dat结果描述符输出变成s1,s2,s3你根本不知道s1代表什么还得回头去数列。几十个特征时简直是灾难。所以配置文件别省。4.3 设计SISSO.in文件这是整个使用过程中最需要动脑的一步。一个典型的SISSO.in长这样5 ! task type: 5表示回归不同版本这个数字的意义不同以示例为准 2 ! Y property: 目标列编号 2 ! nrestart: 重启次数 2 ! nsis: SIS迭代深度 3 ! dimension: 描述符维度 - * / ^2 ^0.5 ^-1 ! 允许的算子 0 ! 是否使用cross validation 10 ! 交叉验证折数 12345 ! 随机种子注意不同版本SISSO.in的格式可能完全不一样甚至从第2版开始task的类型编号都变了。所以一定先看官方示例复制示例再改不要凭记忆硬写。关于operators不同版本里算子表达形式也不一样。有的版本用 - * / ^2 sqrt inv ln这种方式用单词代表有的版本用数字代号。无论如何你要自己确认一遍别想当然。最常出问题的是dimension和nsis的搭配。dimension是最终描述符里保留几项特征nsis是特征生成迭代次数。一般dimension取1~4nsis取1~3。你设dimension5输出公式有五项看起来好像更准但实际上过拟合风险高而且可解释性下降。我的经验是优先从dimension1开始试然后逐步加观察交叉验证误差的下降幅度。如果dimension从2加到3误差只降了一点点说明2就是合适的再往上涨就是噪音了。4.4 交叉验证设置在SISSO里怎么用SISSO支持生成多个模型然后用交叉验证来比较和选择。你可以设置cvtrue并指定折数比如10折SISSO会把数据集分成训练和验证多个部分计算每种维度和特征组合下的预测误差最后输出平均误差最小的描述符。但别忘了SISSO里的交叉验证并不像sklearn里那样自动化“调参”。它只是在你给定的维度参数下评估泛化误差。如果你反复拿验证集去选模型这本身又会引入信息泄漏。所以正确的做法是确定好特征预处理和维度之后再用交叉验证看误差而不是在同一个验证集上反复试不同维度选最低。否则你的实际误差会被低估。如果样本量很小比如少于50我建议直接用留一法交叉验证LOOCV或随机重复多次划分并观察误差的分布。SISSO原始代码里没提供LOOCV但你可以手动把样本拆成几份分别运行SISSO最后汇总误差。5. 实操带隙描述符挖掘全过程5.1 模拟真实任务为了演示完整流程我构建一个模拟数据集假设我们有100种无机晶体材料每个材料有25个特征比如原子半径、电负性、离子化能、配位数、价电子数等目标值是实验带隙。注意这里是为了演示实际跑的时候你可以换成自己的真实数据。模拟数据的第一步是把特征矩阵标准化到均值0方差1这一步非常重要。SISSO里所有特征运算均是基于数值大小如果不同特征尺度差异太大比如半径1.2形成能-5.3那距离计算和稀疏回归会被大尺度特征主导小尺度特征即使重要也可能被忽略。特征标准化的方法很简单用sklearn的StandardScaler或者手动计算z-score都行。标准化之后把150列特征矩阵和目标值写入train.dat。5.2 设置参数并执行假设特征矩阵有25列目标在第26列SISSO.in配置如下以我使用的版本为例你根据自己的版本调整2 ! task type回归 26 ! Y property 列编号 30 ! nrestart建议每跑一次换随机种子多次取稳定结果 2 ! nsis 迭代次数 3 ! dimension 候选最高维度 - * / ^2 ^0.5 ^-1 ! 算子集合 0 ! 不使用自动交叉验证后面手动做保存后运行./sisso屏幕上会刷一堆信息包括读入了多少样本、特征数量、SIS过程中保留了多少特征、稀疏化产生的候选描述符等。我第一次跑的时候光看输出都不知道它在干嘛后来慢慢才明白每段含义。如果你只想看结果刷完之后目录下会生成一个文件比如SISSO_output里面包含最终选出的描述符表达式和系数。5.3 解读输出结果输出文件的格式通常包含描述符特征名每个特征的系数训练集上的预测值拟合优度指标如R²、RMSE比如你看到类似Feature1: r_m * X Feature2: (E_form)^2 Coefficients: 1.23, -0.45 Intercept: 0.12 R2: 0.86 RMSE: 0.18 eV这就意味着你的带隙预测公式为带隙 0.12 1.23 * (r_m * X) - 0.45 * (E_form)^2这个结果就能直接写进论文了。你还可以用这个公式去预测新材料而不需要重新训练。5.4 模型的稳定性验证我强烈建议你在正式产出描述符之前做至少10次独立运行每次用不同的随机种子或不同的重启动参数nrestart然后对比输出的公式。如果每次跑出来的描述符公式都一样或者特征项高度重合说明这个描述符是稳定可靠的。如果你跑了5次几次出来是“AB”几次出来是“CD”那说明特征空间里存在多个等效最优解或者你的特征预处理有问题。此时不应该直接挑一个看着顺眼的发表而是要去分析为什么会出现多个解——是不是特征之间有高度相关性是不是样本量过小是不是算子库引入了一些表达式相近的特征这种情况下我建议做进一步的相关性分析并减少特征集或增加样本量再做SISSO。6. 常见问题与排查实录6.1 编译阶段的问题前面提到的MKL缺失和OpenBLAS链接错误是最普遍的。另一个是编译时出现undefined reference to main这个一般是你直接用g编译了某个源文件而不是用Makefile导致入口缺失。正确做法是进目录跑make。如果你的系统是CentOS或者老一点的Linux自带g版本太低也可能报错。SISSO的代码要求支持C11检查一下g --version如果版本过低可以升级gcc或者改用conda的编译器套件。6.2 运行时内存爆炸特征维度太大、nsis设置太高会导致SIS步骤内存疯涨。如果你观察系统内存占用到80%以上赶紧CtrlC。这里有几个办法一是减少nsis到1二是降低基础特征维度别把200个原始特征全扔进去先做一次相关性筛选或PCA保留30~50个三是用更大内存的服务器跑但我觉得另一个更聪明的办法是分次运行先做SIS保留少量特征把这些特征导出然后再做SO稀疏化。虽然SISSO自动做了两部分但你可以拆开跑降低峰值内存。6.3 结果全是NaN很可能就是train.dat里有空字符串或NaN。用awk检查awk {for(i1;iNF;i) if($iNaN || $i) print Bad line, NR} train.dat另外某些算子比如log(0)、sqrt(负数)会产生NaN。SISSO内部会对特征取值范围做检查但在某些边缘情况下还是会漏。建议在预处理时把所有特征的最小值限制在大于0的范围对需要取对数的特征对可以取负的特征则去掉对数算子。6.4 描述符不稳定出现这个问题的原因我之前说过主要是特征共线性和样本量过小。解决方向有二第一对特征做去相关计算相关矩阵保留代表性特征。第二增加样本量或者采用重采样方法如bootstrap多次运行取频繁出现的特征作为最终描述符。6.5 交叉验证误差怎么比实际误差小很多这是过拟合的表现尤其当你把维度调得过高时。解决办法不是强行压低维度而是用留出集来评估。比如你把样本随机分成80%训练、20%测试只在训练集上跑SISSO再把测试集放进去预测计算测试集误差。这样的误差才有信服力。7. 我的实操心得与建议SISSO这个工具真正用熟了以后会发现它特别“上瘾”——因为你得到的每一个公式都能直接跟物理对上号。我印象很深的一次当时预测一种材料的剪切模量SISSO选出来的描述符居然跟文献报道的Pugh模量比相关性系数高度吻合这比跑出一个超高的深度学习R²更让人兴奋。但我也想提醒各位SISSO不是万能药。它适合特征数量中等、样本量有限、需要解释模型物理意义的场景。如果你的特征数量是几十万那种比如高维基因表达数据SISSO的筛选阶段开销会很高反而不如直接用Lasso或LightGBM先降维。但如果你处理的是材料属性这类中小规模数据SISSO的解释性和可迁移性是黑箱模型无法比的。实操中还有个小技巧运行SISSO之前把你的特征名称写在一个单独的列表里方便对照输出描述符的特征下标。因为SISSO输出有时候默认用列下标表示如果你有prop.dat还好没有的话你会面对一堆数字编号跟猜谜一样。所以prop.dat一定要写而且要准确对应每一列。另外一点关于算子库的选择别贪多。我见过有人把十几种算子全开着跑结果SISSO输出一个特别复杂的表达式里面有exp(sqrt(x/y1))这种项看似贴合实际对数据噪音极其敏感换一批样本完全崩掉。物理模型的美感往往在于简洁。如果你发现一个维度3的描述符和一个维度5的描述符预测误差差不多一定选前者。这也符合奥卡姆剃刀原则。还有一个小技巧如果你的特征列里有些特征本身就是相关性极高的比如晶格常数a和体积V直接相关建议只保留其中一个。特征重复度太高会让SISSO的筛选结果随机波动因为两个等效特征它可能随机选一个保留。保留一个之后结果的确定性会好很多。最后再分享一个扩展应用SISSO输出的线性描述符可以直接作为传统机器学习模型的输入特征。比如你用SISSO在训练集上选出了3个描述符然后把这三个描述符作为随机森林的输入特征往往能得到比直接使用全部特征更好的预测结果同时模型仍有可解释性。这种“物理引导机器学习”的混合思路是目前材料信息学里一个非常实用的模式也推荐你们去试试。我在实际项目中用SISSO找到过几个稳定的描述符后来迁移到类似材料体系依然有效这让我确信它不是简单的数据拟合而是真的在逼近某种潜在的物理规则。如果你的数据里有隐藏的简单规律SISSO就是那把把它凿出来的凿子。不过想要凿得好功夫全在你对数据的理解和对参数的把握上。多跑几次多对比多测试它会在几秒钟之内告诉你答案但答案是否可靠得靠你的判断力。