第1章:材料数据获取与清洗——打好智能发现的第一仗
各位工程师朋友,大家好。我是老张,在材料信息学这个坑里摸爬滚打了七八年。今天咱们聊的这章,是整个智能发现新材料流程里最枯燥、但也是最要命的一环——数据获取与清洗。
你想想看,再牛的AI模型,喂进去的是垃圾,吐出来的只能是更垃圾。我在项目里见过太多团队,模型调得飞起,结果数据有问题,最后白忙活三个月。所以,这一章咱们把地基打牢。
核心观点:材料数据工作占整个项目时间的60%-80%,但决定了90%的成败。
1.1 公开数据库——你的免费材料宝库
做材料数据挖掘,第一个要搞定的就是数据源。我个人最常用的两个公开数据库是 Materials Project 和 OQMD。说白了,它们就是材料界的「维基百科」,但比维基百科靠谱得多。
Materials Project(https://materialsproject.org)
- 由MIT和LBNL联合开发,目前收录了超过15万种无机材料
- 提供晶体结构、能带结构、态密度、弹性常数等计算数据
- 支持Python API(pymatgen库)直接调用,非常方便
OQMD(Open Quantum Materials Database)
- 西北大学出品,收录了超过100万种材料
- 侧重于热力学稳定性数据,形成能计算很全
- 同样提供RESTful API,可以批量查询
我的经验:刚开始用Materials Project时,我习惯直接网页下载CSV。后来发现用API批量拉数据才是正道。一次拉几千条,写个脚本自动处理,省时省力。
来看一段用pymatgen拉数据的示例代码:
from pymatgen.ext.matproj import MPRester
# 注意:需要去官网申请API Key
API_KEY = "你的API_KEY"
with MPRester(API_KEY) as mpr:
# 查询所有含Li和Fe的氧化物
criteria = {"elements": {"$all": ["Li", "Fe"], "$in": ["O"]}}
properties = ["material_id", "formula_pretty", "formation_energy_per_atom", "band_gap"]
data = mpr.query(criteria, properties)
print(f"共找到 {len(data)} 条记录")
for d in data[:5]:
print(d["formula_pretty"], d["formation_energy_per_atom"], d["band_gap"])
注意:API有调用频率限制,免费用户每分钟最多50次请求。批量拉数据时记得加time.sleep(),不然会被封IP。我曾经一次拉5万条数据没加延时,结果被禁了三天...
1.2 实验数据与文献挖掘——从纸堆里淘金
公开数据库虽好,但很多新材料数据还在文献里躺着。怎么把这些数据挖出来?我总结了三板斧。
第一板斧:PDF解析
用Python的pdfplumber或PyMuPDF库,把论文里的表格提取出来。但说实话,准确率也就70%-80%。很多论文的表格是图片格式,那就得用OCR了。
import pdfplumber
import pandas as pd
with pdfplumber.open("paper.pdf") as pdf:
for page in pdf.pages:
tables = page.extract_tables()
for i, table in enumerate(tables):
df = pd.DataFrame(table[1:], columns=table[0])
print(f"第{i+1}个表格提取完成,共{len(df)}行")
第二板斧:NLP命名实体识别
用ChemDataExtractor或自训练的BERT模型,从论文正文中自动识别材料名称、合成条件、性能指标。这个技术门槛稍高,但效果拔群。
第三板斧:人工校验
嗯,这里要实话实说。自动提取的数据,我建议至少抽20%做人工核对。我在一个项目中用NLP提取了2000条催化性能数据,结果发现30%的单位都标错了——有的用mmol/g,有的用μmol/g,差了一千倍。
避坑指南:文献数据挖掘最大的坑是「单位不统一」。我建议在数据入库前,先建立一个单位映射表,把所有数据强制转换成标准单位(比如eV/atom、kJ/mol等)。
1.3 数据清洗与标准化流程
数据拿到手了,接下来就是最磨人的清洗环节。我一般按以下流程走:
- 格式统一——所有化学式转成标准形式(如"Fe2O3"而不是"Fe2O3"或"Fe2 O3")
- 单位转换——建立单位字典,自动转换
- 异常值检测——用IQR或Z-score方法,标记离群点
- 去重——同一材料、同一性能,保留最新或最可靠的数据
- 一致性检查——比如带隙不能为负数,形成能异常高的要标记
来看一个清洗示例:
import pandas as pd
import numpy as np
def clean_material_data(df):
# 1. 化学式标准化
df["formula"] = df["formula"].str.replace(" ", "").str.replace("₂", "2")
# 2. 单位转换(假设原始数据单位是kcal/mol,转成eV/atom)
df["formation_energy"] = df["formation_energy"] * 0.04336
# 3. 异常值检测(Z-score方法)
z_scores = np.abs((df["formation_energy"] - df["formation_energy"].mean()) / df["formation_energy"].std())
df = df[z_scores < 3]
# 4. 去重
df = df.drop_duplicates(subset=["formula", "property"], keep="first")
return df
小技巧:清洗后的数据,我习惯生成一份「清洗日志」,记录删除了多少条、转换了多少单位、标记了多少异常。这样出了问题可以追溯,也方便写论文时交代数据来源。
1.4 数据缺失值处理策略
真实数据永远有缺失。你想想看,1000条材料数据里,可能只有600条有带隙值,800条有形成能。怎么办?
我常用的策略有四种:
| 策略 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 直接删除 | 缺失率<5%,且随机缺失 | 简单快速 | 可能丢失信息 |
| 均值/中位数填充 | 数值型特征,缺失率10%-30% | 保持数据分布 | 降低方差 |
| KNN填充 | 有相似样本可参考 | 利用相似性,效果较好 | 计算量大 |
| 模型预测填充 | 缺失率较高,且特征间相关性强 | 精度最高 | 可能过拟合 |
我个人最常用的是KNN填充。为什么呢?因为材料数据往往有内在规律——比如同族元素、同晶型的材料,性能往往相近。用KNN正好能捕捉这种相似性。
from sklearn.impute import KNNImputer
import numpy as np
# 假设X是特征矩阵,有缺失值
imputer = KNNImputer(n_neighbors=5, weights="distance")
X_imputed = imputer.fit_transform(X)
print(f"填充前缺失值数量: {np.sum(np.isnan(X))}")
print(f"填充后缺失值数量: {np.sum(np.isnan(X_imputed))}")
重要提醒:千万不要在训练集和测试集上一起做填充!一定要先分训练集和测试集,然后在训练集上fit imputer,再transform测试集。否则会造成数据泄露,模型效果虚高。这个坑我踩过,后来审稿人直接拒了...
好了,关于数据获取与清洗,今天就聊到这儿。记住一句话:数据清洗不是一次性工作,而是贯穿整个项目的持续过程。每次加入新数据,都要重新跑一遍清洗流程。
下一章咱们聊聊特征工程——怎么从原始数据中提炼出真正有用的特征。到时候见。
公众号:蓝海资料掘金营,微信deep3321