☰
钙钛矿稳定性预测:SISSO构造新型容许因子与机器学习实战
2026/10/2 5:40:26 网站建设 项目流程

简介:这份PDF文献面向材料计算与机器学习交叉领域的研究者、研究生及材料信息学从业者,聚焦钙钛矿结构稳定性预测这一长期难题。内容系统梳理了传统容许因子tIR的局限,并基于SISSO方法与键价模型提出新型容许因子τBV,借助决策树算法构建验证模型,在376种ABO3型化合物数据集上显著提升分类精度。资源包共1个PDF文件,大小约2.05MB,完整收录了发表于《中国有色金属学报》的论文全文,涵盖钙钛矿结构简介、传统容许因子、新型容许因子、机器学习应用、SISSO方法及键价模型六大知识点,并附有公式推导、数据集特征说明与模型评估对比。目前已有896人学习,适合希望深入理解容许因子演化脉络、掌握SISSO特征筛选与决策树建模流程、并借鉴材料稳定性预测研究范式的读者参考。

1. 钙钛矿稳定性预测:为什么容忍因子不够用,SISSO 能补上哪块短板

钙钛矿太阳能电池这几年在实验室里效率屡创新高,但真正卡住产业化的往往不是效率,而是结构稳定性——同一批配方,有的样品在空气中放两周就相分离,有的却能扛过几百小时湿热老化。做材料筛选的人最头疼的是:候选组分空间太大,靠第一性原理逐个算形成能,算力根本扛不住。传统做法是拿 Goldschmidt 容忍因子 t 先筛一遍,但 t 只用了离子半径这一个几何维度,对 A 位有机阳离子取向、B 位混合价态、八面体倾转这些因素一概视而不见,经常出现「t 落在 0.8~1.0 却依然分解」的翻车案例。

这篇要讲的就是一条更实用的路子:用 SISSO(Sure Independence Screening and Sparsifying Operator)从一批候选描述符里自动搜出可解释的解析表达式,构造一个新型容许因子,再配合机器学习模型做钙钛矿结构稳定性预测。它解决的是「小样本、高维描述符、还要能解释」这三件事同时成立的问题,适合做钙钛矿组分筛选、需要给出物理可读判据的研究生和一线研发。下面从描述符构造一路讲到模型验证和踩坑。

2. 描述符工程:把容忍因子拆成可计算的物理量

2.1 为什么不能只喂离子半径

Goldschmidt 容忍因子 t = (r_A + r_O) / (√2 (r_B + r_O)) 的假设是「刚性球密堆积」,但钙钛矿里 A 位如果是 MA⁺、FA⁺ 这类有机离子,它根本不是球,取向自由度会显著改变有效占据体积。所以第一步不是急着上模型,而是把「几何 + 电子 + 化学键」三个层面的量都算出来,形成一个候选描述符池,让 SISSO 自己去挑。

我一般会构造这几类描述符:

类别代表描述符计算来源说明
几何t、μ(八面体因子 r_B/r_O)、体积失配 ΔV离子半径表基础筛选用
电子A/B 位电负性差、d 电子数、带隙元素数据/DFT反映成键强弱
键合B–O 键长、键价和 BVS晶体结构八面体畸变指标
统计混合熵 ΔS_mix、组分方差配方高熵稳定效应

关键点是:描述符池要宽,但每个都要能算出来。SISSO 的价值在于从几十上百个候选里做稀疏筛选,池子太窄它没得选,池子太宽又容易过拟合,一般控制在 30~80 个比较稳。

2.2 用 pymatgen 批量算几何描述符

下面这段代码演示怎么从 CIF 批量提取容忍因子和八面体因子。假设你手上有一批钙钛矿 CIF 文件。

import os import numpy as np from pymatgen.core import Structure from pymatgen.analysis.local_env import CrystalNN # 离子半径(Shannon 半径,单位 Å),按配位数取 R = { "Cs": 1.67, "MA": 2.17, "FA": 2.53, # A 位有效半径 "Pb": 1.19, "Sn": 1.10, # B 位 "I": 2.20, "Br": 1.96, "Cl": 1.81, # X 位 } def tolerance_factor(rA, rB, rX): return (rA + rX) / (np.sqrt(2) * (rB + rX)) def octahedral_factor(rB, rX): return rB / rX def extract_descriptors(cif_path, a_site, b_site, x_site): s = Structure.from_file(cif_path) rA, rB, rX = R[a_site], R[b_site], R[x_site] t = tolerance_factor(rA, rB, rX) mu = octahedral_factor(rB, rX) # 用 CrystalNN 找 B 位最近邻,算平均 B-X 键长 cnn = CrystalNN() bx_lengths = [] for i, site in enumerate(s): if site.species_string.startswith(b_site): nn = cnn.get_nn_info(s, i) for n in nn: if n["site"].species_string.startswith(x_site): bx_lengths.append(n["weight"] * s.get_distance(i, n["site_index"])) mean_bx = np.mean(bx_lengths) if bx_lengths else np.nan return {"t": t, "mu": mu, "mean_BX": mean_bx} # 批量处理 rows = [] for f in os.listdir("cifs"): if f.endswith(".cif"): d = extract_descriptors(os.path.join("cifs", f), "Cs", "Pb", "I") d["file"] = f rows.append(d) print(rows[:2])

逻辑说明:tolerance_factor和octahedral_factor是纯几何公式,直接套离子半径;CrystalNN用来在真实晶体结构里找 B 位最近的 X 原子,算平均键长,比单纯用半径和更贴近实际畸变。参数上,R字典里的半径要和你用的配位数一致,Shannon 半径同一离子不同配位数能差 0.1 Å 以上,混用会直接污染描述符。CrystalNN的weight是键合权重,乘上距离相当于加权平均键长,比简单平均更稳。

注意:有机 A 位离子(MA/FA)没有标准 Shannon 半径,文献里常用有效半径或动力学半径,选哪套要在全文保持一致,否则 SISSO 搜出来的表达式没法复现。

3. SISSO 筛选与新型容许因子构造

3.1 SISSO 到底在做什么

SISSO 分两步:Sure Independence Screening(SIS)先按与目标量的相关性给所有候选描述符排序,Sparsifying Operator(SO)再用稀疏化方法(如 L1 正则或正交匹配追踪)从排序后的组合里挑出最优的低维表达式。它的输出不是黑箱权重,而是一个显式公式,比如t_new = t * (1 + a*ΔV) / (1 + b*μ)这种形式,物理上能解释。

对稳定性预测,目标量 y 一般取「形成能」或「分解能」的负值(越大越稳),或者直接用 0/1 标签做分类。回归任务更适合 SISSO,因为它需要连续目标来搜表达式。

3.2 跑通 SISSO 的最小流程

SISSO 官方是 Fortran 实现,也有 Python 封装sissopp。下面给一个用 Python 接口跑回归的最小例子。

import numpy as np from sissopp import SISSO, FeatureSpace # X: (n_samples, n_features) 描述符矩阵 # y: (n_samples,) 稳定性目标,比如负形成能 X = np.loadtxt("descriptors.csv", delimiter=",", skiprows=1) y = np.loadtxt("target.csv") # 特征空间:允许一元、二元组合,最多 2 次幂 fs = FeatureSpace( n_features=X.shape[1], n_samples=X.shape[0], max_comp=2, # 最多两个描述符组合 max_power=2, # 允许平方项 op_set="standard", # +, -, *, /, sqrt 等 ) fs.set_features(X) model = SISSO( feature_space=fs, n_dim=2, # 搜 2 维表达式 n_residual=1, # 残差迭代次数 max_terms=5, # 每维最多 5 项 ) model.fit(y) # 输出最优表达式 print(model.best_model)

逻辑说明:FeatureSpace负责把原始描述符扩展成组合特征,max_comp=2表示允许两个描述符相乘/相除,max_power=2允许平方,op_set="standard"包含加减乘除和开方。n_dim=2是最终表达式用两个项,维数越高拟合越好但越容易过拟合,小样本(<100)建议从 1~2 维试起。n_residual是残差迭代,SISSO 会先拟合主项再对残差继续搜,一般设 1~2。

跑完后你会拿到类似t_new = t - 0.32*ΔV + 0.15*μ的表达式,这就是新型容许因子的雏形。接下来要验证它是否真的比传统 t 更能区分稳定/不稳定。

3.3 新型容许因子的验证设计

验证不能只看训练集 R²,要做三件事:

  1. 阈值扫描:把 t_new 从低到高扫,看稳定/不稳定样本的分离度,找最佳分类阈值。
  2. 交叉验证:留一法或 5 折,看表达式在新样本上的泛化。
  3. 对比基线:和传统 t、μ 单独用时的 AUC/准确率对比。
from sklearn.model_selection import cross_val_score from sklearn.linear_model import LogisticRegression from sklearn.metrics import roc_auc_score # 用 SISSO 表达式算出的 t_new 作为单特征 t_new = X[:, 0] - 0.32 * X[:, 1] + 0.15 * X[:, 2] # 按实际表达式改 t_new = t_new.reshape(-1, 1) clf = LogisticRegression() auc = cross_val_score(clf, t_new, y_binary, cv=5, scoring="roc_auc") print("t_new AUC:", auc.mean()) # 对比传统 t auc_t = cross_val_score(clf, X[:, [0]], y_binary, cv=5, scoring="roc_auc") print("传统 t AUC:", auc_t.mean())

参数说明:y_binary是稳定性标签(1 稳定 / 0 不稳定),cv=5是 5 折交叉验证,样本少可以换LeaveOneOut。如果 t_new 的 AUC 明显高于传统 t,说明新因子确实抓到了额外信息。注意逻辑回归前最好做标准化,否则系数解释会偏。

4. 机器学习模型选型与训练细节

4.1 小样本下为什么优先树模型和正则化线性模型

钙钛矿稳定性数据集通常只有几十到几百条,深度学习直接上会过拟合到没法看。我一般按这个顺序试:

  • 随机森林 / XGBoost:对特征尺度不敏感,能给出特征重要性,适合快速摸底。
  • LASSO / Ridge:如果描述符之间共线性强,正则化线性模型更稳,系数还能解释。
  • 高斯过程回归:样本极少(<50)时能给不确定性估计,适合主动学习场景。

SISSO 输出的表达式本身就可以作为一个强特征,再喂给这些模型,往往比直接堆原始描述符效果好。

4.2 训练与评估的完整脚本

import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import StratifiedKFold, cross_validate from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline df = pd.read_csv("dataset.csv") X = df.drop(columns=["label", "file"]).values y = df["label"].values pipe = Pipeline([ ("scaler", StandardScaler()), ("clf", RandomForestClassifier( n_estimators=500, max_depth=6, # 小样本限制深度 min_samples_leaf=2, # 防止叶子过纯 random_state=42, )), ]) cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=42) scores = cross_validate(pipe, X, y, cv=cv, scoring=["accuracy", "roc_auc", "f1"]) print({k: v.mean() for k, v in scores.items() if k.startswith("test_")})

逻辑说明:Pipeline把标准化和分类器串起来,避免交叉验证时标准化泄漏。max_depth=6和min_samples_leaf=2是给小样本加的正则,样本过百可以适当放宽。StratifiedKFold保证每折里稳定/不稳定比例一致,否则 AUC 会虚高。评估至少看 accuracy、AUC、F1 三个,单看 accuracy 在类别不平衡时会骗人。

注意:如果数据里稳定样本远多于不稳定,先做重采样或调class_weight="balanced",否则模型会倾向于全预测稳定。

5. 避坑与排查:那些让结果不可复现的细节

5.1 描述符量纲不统一导致 SISSO 搜出垃圾表达式

现象:SISSO 输出的表达式里出现巨大系数,比如1e5 * ΔV,物理上没法解释。原因:不同描述符量纲差几个数量级(比如体积失配是小数,键长是几 Å),SISSO 的组合运算会被大量纲项主导。解决:进 SISSO 前对所有描述符做标准化(z-score)或归一化到 [0,1],并在论文里注明。标准化后系数大小才有可比性。

5.2 用形成能当标签时忽略了温度修正

现象:模型在 0 K 数据上表现很好,但预测室温稳定性时准确率暴跌。原因:DFT 形成能是 0 K 静态值,实际稳定性受熵、声子、湿度影响,直接用会系统性偏移。解决:要么在标签里加入熵修正项(如 ΔG = ΔH - TΔS),要么在讨论里明确模型只适用于 0 K 趋势判断,别过度声称室温预测能力。

5.3 交叉验证时把同一配方的不同样本分到训练和测试

现象:交叉验证 AUC 0.95,换一批新配方测试掉到 0.6。原因:同一化学式的不同晶胞或不同计算设置被随机分到两边,造成信息泄漏。解决:按化学式或按 A 位元素做 group split,用GroupKFold,保证同一族配方只出现在一边。

5.4 SISSO 维数选太高导致过拟合

现象:训练集 R² 0.98,留一验证 R² 0.3。原因:n_dim设太大,表达式项数过多,把噪声也拟合进去了。解决:从n_dim=1开始,每次加一维看验证误差,选验证误差最低的维数。小样本(<80)通常 1~2 维就够。

5.5 忽略特征间的物理相关性,搜出无法解释的项

现象:表达式里出现t / μ这种组合,但物理上 t 和 μ 本来就相关,除完没意义。原因:SISSO 只优化统计拟合,不管物理合理性。解决:搜完后人工审查每一项,去掉物理上说不通的组合,或者在建特征空间时限制运算符集合(比如禁用除法)。

6. 进阶技巧:用主动学习把 SISSO 表达式迭代到更稳

走到这一步,你手上应该有一个能跑通的最小闭环:描述符 → SISSO → 新因子 → ML 验证。但真实项目里最贵的不是算模型,而是决定下一个该算哪个配方。我的习惯是把 SISSO 表达式当成先验,用高斯过程回归给候选空间打不确定性,挑「预测稳但不确定度高」的样本去补 DFT,补完再重新跑 SISSO,通常两三轮就能把表达式收敛到比较可信的形式。

具体做法:先用现有数据训一个 GPR,对未标注的候选配方预测均值和方差,按mean + k * std(k 取 1~2)排序,取前 10~20 个去算。每轮补完数据后重跑 SISSO,观察表达式结构是否稳定——如果连续两轮搜出来的项基本一致,说明描述符池和维数选对了;如果每轮都大变,多半是样本太少或描述符噪声太大。

一个容易忽略的验证技巧:把 SISSO 表达式在独立文献数据集上测一遍。自己切分的数据再干净也有偏,找一篇别人发表的、体系相近的钙钛矿稳定性数据,直接套你的 t_new 算 AUC,能过 0.75 才说明这个因子有迁移性。我吃过亏,早期只在自己数据上交叉验证,投出去被审稿人用外部数据一测就露馅。后来养成习惯,表达式定稿前必找外部数据验一次,哪怕只有二三十条。

最后一句实在话:SISSO 不是万能钥匙,它擅长的是从一堆你能算出来的量里挑出简洁组合,前提是你得先把物理上说得通的描述符喂进去。描述符池建歪了,SISSO 只会帮你把歪的东西拟合得更漂亮。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询