简介:MAST-ML(Materials Simulation Toolkit for Machine Learning)是一款面向材料科学与机器学习交叉领域的开源工具包,适合材料研究者、计算材料学方向的研究生及希望将AI方法引入材料属性预测的工程师使用。资源包共326个文件,约43.6MB,以rst文档、table数据表、py脚本、ipynb示例笔记本为主,辅以xlsx数据、png图表、css/js/字体等文档站点资源,覆盖数据预处理、特征工程、模型训练、评估验证与部署应用等完整流程。工具包支持线性回归、决策树、随机森林、支持向量机与神经网络等算法,并提供交叉验证、网格搜索、R²分数、均方误差等评估手段,帮助用户从化学组成与结构特征出发构建可复用的预测模型。目前已有192人学习下载,适合作为材料信息学入门与项目实践的参考工具,便于快速理解从原始数据到模型部署的完整链路。
1. 材料仿真遇上机器学习:MAST-ML 到底解决谁的痛点
如果你做过材料计算,大概率经历过这种循环:VASP 或 LAMMPS 跑了几十上百个结构,得到一个 CSV,然后手动清洗、划分训练集、调随机森林、画 parity plot,换一种材料体系又重来一遍。这套流程本身不难,难的是它琐碎、重复、且极易在数据划分和特征工程上翻车。MAST-ML(Materials Simulation Toolkit for Machine Learning)就是冲着这个场景来的——它把材料仿真数据的读取、清洗、特征化、模型训练、交叉验证和结果可视化打包成一套可配置的 Python 工具链,让你把精力放在材料问题上,而不是反复写胶水代码。
这个工具包适合三类人:一是做第一性原理或分子动力学、手里已经攒了一批计算结果的研究生;二是想把机器学习引入材料筛选、但不想从零搭 pipeline 的工程师;三是需要做机器学习课程设计、又希望案例有真实物理背景的学生。它不要求你先成为机器学习专家,但你得能看懂自己的数据结构,知道哪一列是目标值、哪些列是描述符。接下来我会按「装什么、怎么配、怎么跑、哪里容易翻车」的顺序,把 MAST-ML 的落地路径讲清楚。
2. 把 MAST-ML 跑起来:环境、数据格式与最小可运行配置
2.1 安装路径选择与依赖版本控制
MAST-ML 是纯 Python 项目,常见做法是用 conda 建独立环境,避免和系统里的 numpy、scikit-learn 打架。我一般会锁定 Python 3.8 到 3.10 这个区间,太新的版本有时会在 scikit-learn 的某些接口上出兼容问题。下面这套命令是我在 Linux 和 macOS 上都验证过的顺序:
# 创建独立环境,python 版本建议 3.9 conda create -n mastml python=3.9 -y conda activate mastml # 先装科学计算底座,再装 mastml pip install numpy pandas scikit-learn matplotlib seaborn pip install mastml # 验证是否装好 python -c "import mastml; print(mastml.__version__)"逻辑说明:先建环境是为了隔离依赖,numpy和scikit-learn手动装一遍是为了让 pip 解析器优先选稳定版本,而不是被 mastml 的宽松依赖带到最新版。参数上,python=3.9是折中值,3.8 偏旧、3.11 以上部分 sklearn 接口有变动。如果你在 Windows 上,建议用 WSL2 而不是原生 conda,因为 MAST-ML 的部分并行和文件路径处理在 Linux 下更顺。
装完之后别急着跑大项目,先用官方自带的小数据集做冒烟测试。MAST-ML 的典型入口是MASTMLearner类,配合一个 YAML 配置文件。下面是一个最小配置,用来跑通「读 CSV → 划分 → 随机森林 → 输出指标」这条链路:
# minimal_mastml.yaml data: filename: sample_data.csv target_column: band_gap ignore_columns: [material_id, formula] features: - column: volume - column: electronegativity - column: atomic_radius split: test_size: 0.2 random_state: 42 models: - name: RandomForestRegressor kwargs: n_estimators: 200 max_depth: 10 metrics: - r2 - rmse - mae逻辑说明:target_column告诉工具包哪一列是要预测的物理量,ignore_columns是必须显式排除的 ID 类字段,否则模型会把编号当成特征学进去。split里的random_state固定住,是为了让每次划分一致,方便复现。models下可以挂多个模型,MAST-ML 会依次训练并汇总指标。参数上,n_estimators=200和max_depth=10是材料小数据集(几百到几千条)的常用起点,数据量再大可以往上加树的数量,但深度要控制,否则容易过拟合。
2.2 数据格式的硬性要求与清洗边界
MAST-ML 对输入数据的核心要求就一条:一行一个样本,一列一个变量,目标列必须是数值型。听起来简单,但材料仿真数据常见的坑是:同一个化学式出现多次、某些描述符列全是 NaN、目标值有单位后缀(比如 "1.2 eV")。这些都得在进 MAST-ML 之前处理掉。我一般会先跑一段 pandas 做体检:
import pandas as pd df = pd.read_csv("raw_simulation_results.csv") # 看缺失比例 missing_ratio = df.isnull().mean().sort_values(ascending=False) print(missing_ratio[missing_ratio > 0]) # 看目标列是否混入非数值 df["band_gap"] = pd.to_numeric(df["band_gap"], errors="coerce") print("目标列转换后缺失数:", df["band_gap"].isnull().sum()) # 去掉目标缺失的行,描述符缺失用中位数补 df = df.dropna(subset=["band_gap"]) df = df.fillna(df.median(numeric_only=True)) df.to_csv("sample_data.csv", index=False)逻辑说明:pd.to_numeric加errors="coerce"能把带单位的字符串变成 NaN,这样你就能看到到底有多少条脏数据。目标列缺失的行必须删,因为没法监督学习;描述符缺失可以用中位数补,但补之前要确认缺失比例不超过 10%,否则这个特征本身就不该用。参数上,numeric_only=True是防止对字符串列求中位数报错。这一步做完,你得到的sample_data.csv才是 MAST-ML 能直接吃的格式。
2.3 用 MAST-ML 跑通第一个回归任务
配置和数据都齐了之后,运行方式有两种:命令行和 Python 脚本。我倾向用脚本,因为方便调试和加日志:
from mastml.mastml import MASTML from mastml.data_loader import DataLoader # 加载配置 loader = DataLoader("minimal_mastml.yaml") data = loader.load() # 初始化学习器并运行 mastml = MASTML(data=data, config="minimal_mastml.yaml") results = mastml.run() # 输出指标和特征重要性 print(results["metrics"]) print(results["feature_importances"])逻辑说明:DataLoader负责解析 YAML 和 CSV,MASTML对象把整个流程串起来。run()返回的字典里通常包含每个模型的交叉验证指标、测试集预测值和特征重要性。参数上,如果你在 YAML 里配了多个模型,results["metrics"]会是一个按模型名索引的结构。第一次跑建议只留一个模型,确认链路通了再加。跑完之后重点看两个东西:测试集 R² 和特征重要性排序。如果 R² 是负的,说明模型还不如直接猜均值,大概率是特征列选错了或者数据泄漏。
3. 特征工程与模型选择:材料描述符怎么配才不翻车
3.1 材料仿真里哪些列能当特征,哪些必须扔
材料数据的特征大致分三类:成分特征(元素电负性、原子半径、价电子数)、结构特征(晶格常数、体积、配位数)、工艺特征(温度、压力、退火时间)。MAST-ML 本身不生成这些特征,它假设你已经在 CSV 里准备好了。常见做法是先用 pymatgen 或 matminer 做一轮成分和结构特征化,导出成表格,再喂给 MAST-ML。这里有个血泪经验:不要把形成能、带隙这类目标值的中间计算量当特征,比如你预测带隙,却把「带隙计算时用的 k 点密度」放进去,模型会学到虚假相关,交叉验证分数虚高,换一批数据直接崩。
判断一个特征能不能用,我一般问三个问题:这个量在预测时能不能提前拿到?它和目标值有没有物理上的因果链?它的数值范围会不会因为计算参数不同而漂移?三个都过关才留下。下面这段代码演示用 matminer 生成成分特征并和原始数据合并:
from matminer.featurizers.composition import ElementProperty from pymatgen.core import Composition import pandas as pd df = pd.read_csv("sample_data.csv") # 用化学式生成成分特征 featurizer = ElementProperty.from_preset("magpie") df["composition"] = df["formula"].apply(Composition) features = df["composition"].apply(lambda x: featurizer.featurize(x)) feature_df = pd.DataFrame(features.tolist(), columns=featurizer.feature_labels()) # 合并回原表,去掉原始化学式列 df = pd.concat([df.drop(columns=["composition"]), feature_df], axis=1) df.to_csv("sample_data_with_features.csv", index=False)逻辑说明:ElementProperty.from_preset("magpie")会生成一批基于元素统计的描述符,适合成分-性能预测。featurize返回的是列表,转成 DataFrame 后才能和原表按行对齐。参数上,magpie预设包含约 130 个特征,对小数据集来说偏多,后面需要做特征筛选。合并时用axis=1保证行索引一致,否则会出现 NaN 行。
3.2 交叉验证策略:材料数据为什么不能随便 shuffle
材料数据有个特点:同一个体系的不同掺杂浓度、不同温度点之间高度相关。如果你直接train_test_split(shuffle=True),训练集和测试集里可能同时出现同一个体系的数据,模型相当于在「背题」,测试分数会虚高。常见做法是用GroupKFold,把同一个材料体系或同一个计算项目编成一组,保证整组要么在训练集、要么在测试集。MAST-ML 的 YAML 里可以配 group 列:
split: method: GroupKFold n_splits: 5 group_column: system_id逻辑说明:group_column指向你数据里标识材料体系的列,比如system_id或project_id。n_splits=5是常用值,数据量少于 200 条时建议降到 3。这样切出来的每一折,测试集里的体系都是训练集没见过的,指标更接近真实泛化能力。如果你不确定该不该分组,可以先跑一次普通 KFold 和一次 GroupKFold,如果两者 R² 差距超过 0.15,说明数据泄漏严重,必须用分组。
3.3 模型选型:从线性回归到集成模型的取舍
MAST-ML 支持 scikit-learn 的大部分回归和分类器。材料小数据集(几百条)上,我一般按这个顺序试:Ridge 回归 → 随机森林 → Gradient Boosting → 如果数据量上千再考虑 XGBoost 或神经网络。Ridge 作为基线,能快速告诉你特征和目标的线性关系有多强;随机森林对非线性、特征交互更敏感,且自带特征重要性;Gradient Boosting 通常在中等数据量上表现最好,但调参更敏感。下面是一个多模型对比的配置片段:
models: - name: Ridge kwargs: alpha: 1.0 - name: RandomForestRegressor kwargs: n_estimators: 300 max_depth: 12 min_samples_leaf: 2 - name: GradientBoostingRegressor kwargs: n_estimators: 200 learning_rate: 0.05 max_depth: 4逻辑说明:Ridge的alpha控制正则化强度,特征多的时候可以调到 10 或 100。随机森林的min_samples_leaf=2是防止叶子节点只有一个样本,材料数据噪声大,这个参数能明显降过拟合。Gradient Boosting 的learning_rate=0.05配n_estimators=200是慢学习率+多树的经典组合,比默认的 0.1 更稳。跑完对比时,不要只看 R²,还要看 RMSE 的物理量纲——比如带隙预测 RMSE 0.3 eV 和 0.1 eV 是完全不同的可用性。
4. 避坑与排查:MAST-ML 落地时最容易翻车的五个地方
4.1 现象:训练集 R² 0.95,测试集 R² 负值
原因:最常见的是数据泄漏,比如特征里混入了目标值的计算参数,或者同一个体系的数据同时出现在训练和测试集。另一个可能是特征列里有一列是 ID 或时间戳,模型把它当成了强特征。
解决:先检查ignore_columns有没有漏掉 ID 类字段;再把 split 改成 GroupKFold 并指定 group 列;最后逐个删特征做消融,看哪个特征一去掉测试分数就正常。我一般会先跑一次只有 3 个物理意义明确特征的模型,确认基线正常后再加特征。
4.2 现象:MAST-ML 报错 "could not convert string to float"
原因:CSV 里某些列混了字符串,比如化学式、单位后缀、或者空值被读成了 "NA"。MAST-ML 在特征矩阵组装阶段会强制转 float,遇到非数值就崩。
解决:在进 MAST-ML 之前用 pandas 做一次全表apply(pd.to_numeric, errors="coerce"),把非数值列找出来。如果是分类变量,需要先做 one-hot 编码;如果是单位问题,在数据导出阶段就统一量纲。别指望 MAST-ML 帮你做类型推断,它不做这个。
4.3 现象:特征重要性全是 0,或者排序和物理直觉完全相反
原因:特征量纲差异太大,比如体积是几百、电负性是 0 到 4,树模型虽然对量纲不敏感,但线性模型和某些重要性计算会受影响。另一个原因是特征之间高度共线,模型把重要性随机分给了几个相关特征。
解决:对线性模型做标准化,MAST-ML 的 YAML 里可以配scale_features: true。对共线性问题,先算特征间的 Pearson 相关系数,把相关系数大于 0.95 的成对特征删掉一个。如果重要性排序和物理直觉相反,先别急着否定模型,检查一下目标列有没有取错、单位有没有搞混。
4.4 现象:交叉验证分数波动极大,换一个 random_state 就差 0.2
原因:数据量太小,或者分组不合理。材料数据集经常只有几十到几百条,5 折交叉验证每一折的测试集可能只有十几条,指标方差自然大。
解决:把n_splits降到 3,或者改用留一法(LOO)看整体趋势。更稳的做法是做多次不同 random_state 的交叉验证,取均值和标准差一起报告。如果标准差超过均值的 20%,说明模型在这个数据量下不可靠,要么补数据,要么简化模型。
4.5 现象:跑完 MAST-ML 没有报错,但输出目录里没有预测结果文件
原因:YAML 里没有配output路径,或者配了但目录不存在。MAST-ML 默认可能只打印指标,不落盘预测值。
解决:在 YAML 里显式加output: ./results,并确保目录提前建好。另外检查metrics列表里有没有你想要的具体指标名,有些指标需要额外装sklearn的扩展。跑完之后重点看results目录下的predictions.csv和metrics.csv,这两个文件是后续分析和画图的基础。
5. 进阶技巧:用 MAST-ML 做特征筛选与不确定性估计
5.1 基于排列重要性的特征筛选
随机森林自带的特征重要性有个问题:对高基数特征有偏。更稳的做法是排列重要性(permutation importance),它直接看打乱某个特征后模型误差增加多少。MAST-ML 本身不直接提供这个,但你可以拿它输出的训练好的模型,配合 scikit-learn 的permutation_importance来做:
from sklearn.inspection import permutation_importance from mastml.mastml import MASTML mastml = MASTML(data=data, config="minimal_mastml.yaml") results = mastml.run() # 取第一个模型和测试集 model = results["models"][0] X_test = results["X_test"] y_test = results["y_test"] perm = permutation_importance(model, X_test, y_test, n_repeats=30, random_state=42) for i in perm.importances_mean.argsort()[::-1][:10]: print(f"{X_test.columns[i]}: {perm.importances_mean[i]:.4f} +/- {perm.importances_std[i]:.4f}")逻辑说明:n_repeats=30表示每个特征打乱 30 次取平均,次数越多越稳但越慢。输出里importances_mean是误差增加的平均值,越大越重要;importances_std是波动,如果某个特征均值大但标准差也大,说明它的重要性不稳定。我一般会保留重要性均值大于 0.01 且标准差小于均值一半的特征,其余删掉重训。这样通常能把特征数从上百降到二三十,模型更简单、泛化更好。
5.2 用集成模型做预测区间估计
材料筛选场景里,光给一个预测值不够,你还想知道这个预测有多可信。常见做法是用随机森林的每棵树分别预测,取分位数作为区间:
import numpy as np # 假设 rf 是训练好的 RandomForestRegressor predictions = np.array([tree.predict(X_test) for tree in model.estimators_]) lower = np.percentile(predictions, 10, axis=0) upper = np.percentile(predictions, 90, axis=0) # 统计测试集里真实值落在区间内的比例 coverage = np.mean((y_test >= lower) & (y_test <= upper)) print(f"80% 预测区间覆盖率: {coverage:.2f}")逻辑说明:每棵树的预测可以看作对同一问题的一次采样,分位数区间反映了模型内部的意见分歧。10和90分位数对应 80% 区间,如果你想要 90% 区间就改成 5 和 95。coverage是实际覆盖率,理想情况下应该接近 0.8。如果覆盖率明显偏低,说明模型过于自信,需要增加树的数量或放宽区间。这个技巧在材料筛选里很实用:你可以只对预测区间窄、且预测值超过阈值的候选材料做后续实验,省下大量计算资源。
5.3 我踩过的坑和现在的习惯
最后说一个我自己的教训。早期用 MAST-ML 的时候,我图省事,把所有能拿到的列都塞进特征,跑出来 R² 0.9 多,兴奋地拿去汇报。结果换了一个批次的仿真数据,R² 直接掉到 0.3。后来排查发现,有一列是「计算任务提交时间」,它和目标值没有物理关系,但因为不同批次的参数设置不同,它间接编码了批次信息,模型学到的其实是「哪个批次」。从那以后,我养成了一个习惯:任何特征进模型之前,先问一句「这个量在真实预测场景里能不能提前拿到,且和目标值有物理因果链」。答不上来的,一律删掉。另外,我现在会固定把数据集按材料体系分组,先跑一个只有三五个核心物理特征的小模型作为基线,基线正常了再逐步加特征,每加一批就记录一次交叉验证指标。这样即使翻车,也能快速定位是哪一批特征引入的问题。
MAST-ML 这个工具包本身不复杂,它的价值在于把材料机器学习的标准流程固化下来,让你少写重复代码、少犯低级错误。但工具永远替代不了对数据和物理问题的判断。希望帮到你。
本文还有配套的精品资源,点击获取