简介这份PDF文献面向材料计算与机器学习方向的研究者、研究生及材料信息学从业者聚焦钙钛矿结构稳定性预测这一长期难题。内容系统梳理了传统容许因子tIR的局限并基于SISSO方法与键价模型提出新型容许因子τBV配合决策树算法构建验证模型在376种ABO3型化合物样本上显著提升分类精度。资源包共1个PDF文件大小约2.05MB为期刊论文全文含摘要、方法、数据集与实验对比等完整章节便于精读与引用。目前已有896人学习下载适合需要理解容许因子演化脉络、掌握SISSO特征筛选流程或借鉴机器学习建模思路的读者可作为课题入门与论文写作的参考文献。1. 钙钛矿稳定性预测为什么传统容许因子不够用SISSO 能补上哪块短板做钙钛矿光伏或发光器件的同行大概都有过这种体验同样的 ABX₃ 配方别人旋涂出来能稳定存放几个月自己重复却几天就相变发黄。问题往往不在手套箱水氧值而在于你选的这个组分本身在热力学上就站在悬崖边上。传统 Goldschmidt 容许因子 t 和八面体因子 μ 是最常用的两个判据但它们只用了离子半径这一个维度的信息对 A 位有机大分子、混合阳离子、卤素掺杂这些真实体系经常给出模棱两可的结论。这份《基于SISSO和机器学习方法的钙钛矿结构的稳定性预测新型容许因子建立与验证》就是冲着这个痛点来的——它用 SISSOSure Independence Screening and Sparsifying Operator从高维描述符里自动筛出可解释的解析表达式再结合机器学习模型做稳定性分类最终给出一个比传统 t 因子更准的新型容许因子。适合正在做组分筛选、需要快速判断候选钙钛矿能不能稳定合成的研究生和一线研发也适合想把可解释机器学习引入材料设计的工程师。它不是纯理论综述而是一套能复现的建模流程加验证结果。2. SISSO 特征筛选与新型容许因子构建从描述符池到解析表达式2.1 为什么选 SISSO 而不是直接上随机森林或 XGBoost钙钛矿稳定性预测的难点在于样本量通常只有几百到几千条而候选描述符可以轻松堆到几十维——离子半径、电负性、容忍因子、八面体因子、原子序数、价态、离子极化率、键长、形成能等等。这种「小样本高维」场景下树模型很容易过拟合而且输出的是黑匣子你没法从模型里读出物理意义。SISSO 的思路不一样它先用相关性筛选把描述符空间压缩再用稀疏化算子做符号回归最终给你一个显式的数学表达式。这个表达式本身就是新型容许因子的候选形式既能预测又能解释。常见做法是先用 SISSO 做一轮特征筛选把筛出来的 3 到 5 个核心描述符再喂给随机森林或梯度提升树做分类验证。这样既有可解释性又有集成模型的稳健性。我一般会建议把 SISSO 的输出当作「物理先验」而不是直接拿它的表达式去硬拟合所有数据。2.2 描述符池的构建与 SISSO 输入文件格式SISSO 的输入是一个矩阵文件每行一个样本每列一个描述符最后一列是目标值稳定性标签通常 1 表示稳定、0 表示不稳定。描述符池的构建直接决定最终表达式的物理合理性。以下是一个典型的描述符生成脚本基于 pymatgen 从 CIF 或结构文件中提取import numpy as np import pandas as pd from pymatgen.core import Structure, Element def build_descriptor_pool(cif_list, label_list): cif_list: 结构文件路径列表 label_list: 对应的稳定性标签1/0 返回: DataFrame每行一个样本列为描述符 records [] for cif_path, label in zip(cif_list, label_list): s Structure.from_file(cif_path) # 按元素种类分组假设 ABX3 中 A 位为最大半径阳离子 sites sorted(s.sites, keylambda x: x.specie.atomic_radius or 0, reverseTrue) A sites[0].specie B sites[1].specie X sites[2].specie r_A A.atomic_radius r_B B.atomic_radius r_X X.atomic_radius # 传统容忍因子与八面体因子 t (r_A r_X) / (np.sqrt(2) * (r_B r_X)) mu r_B / r_X # 扩展描述符电负性差、价态、极化率 chi_A, chi_B, chi_X A.X, B.X, X.X en_diff abs(chi_A - chi_X) abs(chi_B - chi_X) # 平均价态简化处理实际需从化学式解析 val_A A.group val_B B.group records.append({ r_A: r_A, r_B: r_B, r_X: r_X, t: t, mu: mu, en_diff: en_diff, val_A: val_A, val_B: val_B, label: label }) return pd.DataFrame(records) # 输出 SISSO 可读格式空格分隔最后一列为标签 df build_descriptor_pool(cif_files, labels) df.to_csv(sisso_input.txt, sep , indexFalse, headerFalse)这段脚本的逻辑是从结构文件里解析出 A、B、X 三种位点的元素计算离子半径、电负性、价态等基础属性再组合成传统因子和扩展描述符。参数说明上atomic_radius用的是 pymatgen 内置的 Shannon 半径如果你有自己的一套离子半径表建议替换掉因为不同来源的半径值会直接影响 t 和 μ 的数值。label列必须放在最后一列SISSO 默认最后一列是目标变量。输出用空格分隔、不带表头这是 SISSO 的标准输入格式。2.3 SISSO 运行参数与表达式筛选SISSO 的编译和运行在 Linux 下比较顺Windows 下需要 MinGW 或 WSL。核心参数在SISSO.in里配置# SISSO.in 关键参数 NSAMPLE 500 # 样本数 NDIM 10 # 描述符维度 NFEAT 2 # 最终表达式中特征数上限 NPHASE 3 # 稀疏化阶段数 OCCUR 1 # 是否允许重复使用同一描述符NFEAT是最关键的参数。设成 1 到 2 时SISSO 会给出最简表达式物理意义最清晰但拟合精度可能不够设成 3 到 4 时精度上去了但表达式会变得复杂解释成本增加。我的经验是先用NFEAT2跑一轮看筛选出的描述符是否包含传统 t 因子或 μ 因子如果包含说明你的描述符池构建合理如果不包含检查一下半径数据或标签质量。运行命令./SISSO sisso.log 21输出文件SISSO.out里会列出筛选出的描述符组合和对应的 RMSE。你需要关注的是Feature 1、Feature 2这些行它们就是新型容许因子的组成项。常见的结果形式是t和en_diff的组合或者mu和val_B的组合具体取决于你的数据集。提示SISSO 对输入数据的量纲很敏感。如果某一列描述符的数值范围是 0.1 到 1另一列是 100 到 1000稀疏化时会偏向大数值列。建议在输入前做标准化或者至少在日志里检查一下各列的均值和方差。3. 机器学习分类模型搭建与验证从 SISSO 输出到可复现的预测流程3.1 数据集划分与类别不平衡处理钙钛矿稳定性数据集通常是不平衡的——稳定样本多、不稳定样本少或者反过来。直接拿全量数据训练模型会偏向多数类召回率很难看。常见做法是用 SMOTE 做过采样或者用class_weightbalanced让模型自动调整权重。我一般会先看标签分布如果少数类占比低于 20%就上 SMOTE如果高于 20%直接用类别权重就够了。from sklearn.model_selection import train_test_split, StratifiedKFold from imblearn.over_sampling import SMOTE import pandas as pd df pd.read_csv(sisso_input.txt, sep , headerNone) X df.iloc[:, :-1].values y df.iloc[:, -1].values # 分层划分保证训练集和测试集类别比例一致 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, stratifyy, random_state42 ) # 只在训练集上过采样测试集保持原始分布 smote SMOTE(random_state42) X_train_res, y_train_res smote.fit_resample(X_train, y_train) print(f原始训练集: {X_train.shape}, 过采样后: {X_train_res.shape})这里的关键点是 SMOTE 只能用在训练集上。如果先对全量数据过采样再划分测试集里会混入合成样本评估结果会虚高。这个坑我在早期项目里踩过后来每次划分数据都强制先train_test_split再fit_resample。3.2 随机森林与梯度提升树的对比实验SISSO 筛出的描述符可以直接喂给分类器。以下脚本对比随机森林和 XGBoost 在同一个数据集上的表现from sklearn.ensemble import RandomForestClassifier from xgboost import XGBClassifier from sklearn.metrics import accuracy_score, f1_score, roc_auc_score models { RandomForest: RandomForestClassifier( n_estimators500, max_depth10, random_state42, class_weightbalanced ), XGBoost: XGBClassifier( n_estimators500, max_depth6, learning_rate0.05, subsample0.8, colsample_bytree0.8, random_state42, eval_metriclogloss ) } for name, model in models.items(): model.fit(X_train_res, y_train_res) y_pred model.predict(X_test) y_prob model.predict_proba(X_test)[:, 1] print(f{name}: ACC{accuracy_score(y_test, y_pred):.3f}, fF1{f1_score(y_test, y_pred):.3f}, fAUC{roc_auc_score(y_test, y_prob):.3f})参数上随机森林的n_estimators设 500 通常够用再往上收益递减max_depth控制在 10 以内防止过拟合。XGBoost 的learning_rate设 0.05 配合 500 棵树是比较稳的组合subsample和colsample_bytree设 0.8 能增加泛化能力。如果你的数据集只有几百条建议把n_estimators降到 200 到 300同时把max_depth压到 4 到 5。3.3 交叉验证与新型容许因子的验证方法单次划分的评估结果波动很大尤其是小样本。更稳的做法是 5 折或 10 折分层交叉验证每折都重新做 SMOTE 和训练from sklearn.model_selection import StratifiedKFold import numpy as np skf StratifiedKFold(n_splits5, shuffleTrue, random_state42) auc_scores [] for train_idx, val_idx in skf.split(X, y): X_tr, X_val X[train_idx], X[val_idx] y_tr, y_val y[train_idx], y[val_idx] X_tr_res, y_tr_res SMOTE(random_state42).fit_resample(X_tr, y_tr) clf RandomForestClassifier(n_estimators300, max_depth8, random_state42) clf.fit(X_tr_res, y_tr_res) y_prob clf.predict_proba(X_val)[:, 1] auc_scores.append(roc_auc_score(y_val, y_prob)) print(f5折AUC: {np.mean(auc_scores):.3f} ± {np.std(auc_scores):.3f})新型容许因子的验证不能只看分类精度。更硬核的做法是拿它去预测一批文献里已知稳定或不稳定的钙钛矿看预测结果和实验报道是否一致。如果 SISSO 给出的表达式在独立测试集上 AUC 能到 0.85 以上基本可以认为它比传统 t 因子有增量价值。如果 AUC 在 0.7 左右说明描述符池里还缺关键变量比如 A 位有机分子的取向熵或者卤素混合的构型熵。注意交叉验证的折数不要设太高。5 折在几百条样本上已经够用10 折会导致每折验证集太小AUC 方差反而变大。4. 避坑与排查SISSO 和机器学习联合建模中最容易翻车的五个地方4.1 描述符量纲不统一导致 SISSO 筛选结果不可解释现象SISSO 输出的表达式里全是原子序数、价态这种大数值描述符离子半径和容忍因子一个都没选上。原因SISSO 的稀疏化算子对数值范围敏感大数值列在回归时天然占优。解决在生成输入文件前对每一列做 z-score 标准化或者至少把半径类描述符统一到 Å 单位、电负性统一到 Pauling 标度。标准化后再跑 SISSO筛选出的描述符会合理得多。4.2 标签定义模糊导致模型学到噪声现象模型在训练集上 AUC 0.95测试集掉到 0.65。原因稳定性标签的定义不统一——有的样本按「实验合成成功」标 1有的按「DFT 形成能为负」标 1两种标准混在一起模型学到的其实是标签来源而不是稳定性本身。解决在构建数据集时明确标签定义要么全用实验合成结果要么全用 DFT 能量判据不要混用。如果必须混用加一列label_source作为描述符让模型自己学来源偏差。4.3 SMOTE 用在全量数据上导致评估虚高现象交叉验证 AUC 0.92但拿独立测试集一跑只有 0.70。原因过采样在划分数据之前做了合成样本同时进入了训练集和测试集测试集里有一半是「假样本」。解决严格按「先划分、后过采样」的顺序测试集永远保持原始分布。这个坑几乎每个做不平衡分类的人都会踩一次记住就行。4.4 特征数 NFEAT 设太大导致表达式过拟合现象SISSO 给出的表达式包含 5 个以上描述符RMSE 很低但拿新数据一算误差很大。原因NFEAT设太大SISSO 为了降低训练误差引入了过多项表达式失去了物理约束。解决把NFEAT控制在 2 到 3优先选包含传统 t 因子或 μ 因子的组合。如果NFEAT2的 RMSE 比NFEAT4高不超过 20%就选 2。4.5 忽略离子半径来源差异导致 t 因子计算偏差现象同一批数据用 Shannon 半径算出的 t 因子和用 pymatgen 默认半径算出的差 0.05 以上稳定性分类结果跟着变。原因不同来源的离子半径表对同一元素的半径值定义不同尤其是 A 位有机阳离子有的按有效半径、有的按范德华半径。解决全流程统一用一套半径表推荐 Shannon 的有效离子半径并在论文或报告中注明来源。如果做混合阳离子体系按占位比例加权平均不要简单取最大或最小。5. 把新型容许因子用起来从预测脚本到独立验证的完整闭环走到这一步你手里应该有了 SISSO 筛出的表达式和训练好的分类器。但真正让这份资源产生价值的是把它变成一个能随时调用的预测脚本。我一般会把 SISSO 表达式硬编码成一个函数输入 A、B、X 的离子属性直接输出稳定性概率。这样在筛选新组分时不用每次都跑一遍 SISSO几秒钟就能过一遍候选列表。def new_tolerance_factor(r_A, r_B, r_X, en_diff): 基于 SISSO 筛选结果的新型容许因子示例形式 实际系数以你的 SISSO.out 输出为准 t (r_A r_X) / (np.sqrt(2) * (r_B r_X)) # SISSO 常见输出形式t 与电负性差的线性组合 tau 0.85 * t 0.15 * en_diff return tau def predict_stability(r_A, r_B, r_X, en_diff, model): tau new_tolerance_factor(r_A, r_B, r_X, en_diff) # 将 tau 和其他描述符拼成模型输入 features np.array([[r_A, r_B, r_X, tau, en_diff]]) prob model.predict_proba(features)[0, 1] return prob # 批量预测候选组分 candidates [ (1.80, 0.65, 1.40, 1.2), # CsPbI3 类似 (2.20, 0.65, 1.40, 1.5), # 更大 A 位 (1.60, 0.65, 1.40, 0.9), # 更小 A 位 ] for c in candidates: prob predict_stability(*c, modelclf) print(fr_A{c[0]}, 稳定概率{prob:.3f})这段脚本的关键在于new_tolerance_factor里的系数。SISSO 输出的表达式通常带具体系数比如0.85*t 0.15*en_diff只是示意你要用自己的SISSO.out里的数值替换。predict_stability把新因子和原始描述符拼在一起喂给分类器这样既保留了 SISSO 的物理洞察又利用了机器学习模型的非线性拟合能力。验证环节我建议做两件事。第一拿一批不在训练集里的文献数据跑一遍看预测概率和实验报道的稳定/不稳定是否一致统计混淆矩阵。第二把新型容许因子和传统 t 因子分别画 ROC 曲线对比 AUC。如果新因子的 AUC 比 t 因子高 0.05 以上说明它确实有增量信息如果只高 0.01 到 0.02那就要谨慎了可能只是数据集偏差带来的假象。还有一个容易被忽略的点新型容许因子的适用范围。SISSO 是在你的训练集上筛出来的如果训练集里全是卤化物钙钛矿拿它去预测硫化物或氧化物钙钛矿大概率不准。我一般会在脚本里加一个域外检测算一下新样本的描述符和训练集中心的马氏距离超过阈值就输出「超出适用域」而不是硬给一个概率。这个习惯是从一次翻车经历来的——当时拿卤化物模型去预测一批氧化物结果全报稳定实验做出来全是杂相。从那以后我每次部署预测脚本都强制走一遍适用域检查宁可少预测几个也不给错误结论。希望帮到你。本文还有配套的精品资源点击获取