4. 材料数据采集与清洗:从数据库到实验台

做材料预测,最怕什么?不是算法不够强,而是数据本身就有问题。我见过太多项目,模型调得漂漂亮亮,一上实验数据就崩盘。说白了,数据采集和清洗才是整个闭环的地基。

这一章,咱们就聊聊怎么从公开数据库拿数据,怎么把实验记录数字化,以及怎么处理那些烦人的缺失值和异常值。

4.1 公开数据库:Materials Project 与 OQMD

先说说两个最常用的数据库。我个人习惯用 Materials Project 做起点,因为它界面友好,数据量大。OQMD 呢,计算细节更丰富,适合做对比验证。

4.1.1 Materials Project 使用要点

这个数据库收录了超过 15 万种无机材料的计算数据。怎么用?我一般通过 API 批量拉取,而不是手动下载。

核心操作:注册 API 密钥 → 用 Python 的 pymatgen 库调用 → 按条件筛选(比如带隙范围、元素种类)

from pymatgen.ext.matproj import MPRester

# 初始化连接
mpr = MPRester("你的API密钥")

# 查询带隙在1.0-2.0 eV之间的氧化物
criteria = {"elements": {"$in": ["O"], "$all": []},
             "band_gap": {"$gte": 1.0, "$lte": 2.0}}
results = mpr.query(criteria, ["material_id", "pretty_formula", "band_gap"])

for r in results[:5]:
    print(f"{r['pretty_formula']}: {r['band_gap']:.2f} eV")

我的经验:别一次性拉取所有字段。我刚开始做的时候,贪多求全,结果数据量太大,本地处理卡死。建议先拉关键字段,后续再补充。

4.1.2 OQMD 的独特价值

OQMD(Open Quantum Materials Database)的特点是计算一致性高。它用统一的 DFT 参数跑出来的数据,做横向对比特别靠谱。

我曾经在两个数据库里查同一个材料体系,发现带隙差了 0.3 eV。为什么会这样?因为计算参数不同。这时候 OQMD 的数据就更可信,因为它所有计算都用了同一套设置。

# OQMD 的 RESTful API 调用示例
import requests

url = "https://oqmd.org/rest/search"
params = {"formula": "TiO2", "fields": "band_gap,formation_energy"}
response = requests.get(url, params=params)
data = response.json()
print(f"TiO2 带隙: {data['data'][0]['band_gap']} eV")

4.2 实验数据数字化:从纸质记录到结构化数据

公开数据库虽好,但很多时候我们得用自己的实验数据。我见过不少实验室,数据还记在纸质本子上。嗯,这里要注意,数字化不是简单打字,而是结构化。

4.2.1 数据采集模板设计

我建议用统一的 Excel 模板或数据库表结构。关键字段包括:

  • 样本标识:唯一编号,比如 "Sample-2024-001"
  • 合成参数:温度、压力、时间、前驱体比例
  • 表征结果:XRD 峰位、SEM 形貌描述、电导率值
  • 元数据:操作人、日期、设备型号

避坑指南:我曾经接手一个项目,实验记录里只写了 "高温烧结",没有具体温度。结果模型训练时,这个字段完全没法用。所以,能量化的尽量量化,别用模糊描述。

4.2.2 自动提取与 OCR 技术

对于已有的 PDF 或扫描件,可以用 OCR 工具提取。我个人习惯用 Tesseract 配合正则表达式。

import pytesseract
from PIL import Image
import re

# 读取扫描件
img = Image.open("experiment_record.png")
text = pytesseract.image_to_string(img, lang='chi_sim')

# 提取温度值
temperatures = re.findall(r'(\d+)\s*°C', text)
print(f"提取到温度: {temperatures}")

小技巧:手写体识别准确率不高。我一般先人工核对关键数据,再用 OCR 做辅助。别完全依赖自动化。

4.3 缺失值处理:别让空值毁了模型

数据采集完了,打开一看,一堆空值。怎么办?三种常见策略:删除、填充、预测。

4.3.1 缺失值类型判断

缺失类型 特征 处理方式
完全随机缺失 无规律,随机空值 直接删除或均值填充
随机缺失 与其他变量相关 回归预测填充
非随机缺失 与缺失值本身相关 需单独建模处理

4.3.2 填充方法选择

我个人最常用的是 KNN 填充。为什么?因为它考虑了样本间的相似性,比简单均值填充靠谱。

from sklearn.impute import KNNImputer
import numpy as np

# 假设 data 是包含缺失值的数组
imputer = KNNImputer(n_neighbors=5)
data_filled = imputer.fit_transform(data)

print(f"填充前缺失数: {np.sum(np.isnan(data))}")
print(f"填充后缺失数: {np.sum(np.isnan(data_filled))}")

注意:如果某个特征的缺失率超过 60%,我建议直接删除这个特征。强行填充只会引入噪声,对模型有害无益。

4.4 异常值检测:揪出捣乱的数据点

数据里总有些"刺头"——异常值。它们可能是测量误差,也可能是真实的新现象。怎么区分?

4.4.1 统计方法

最基础的是 Z-score 方法。我一般设定阈值为 3,超过 3 个标准差的点视为异常。

from scipy import stats
import numpy as np

z_scores = np.abs(stats.zscore(data))
threshold = 3
outliers = np.where(z_scores > threshold)
print(f"检测到 {len(outliers[0])} 个异常值")

4.4.2 基于密度的方法

对于高维数据,我更喜欢用 LOF(Local Outlier Factor)。它能捕捉局部密度异常,适合材料数据这种分布不均匀的场景。

from sklearn.neighbors import LocalOutlierFactor

lof = LocalOutlierFactor(n_neighbors=20, contamination=0.05)
outlier_labels = lof.fit_predict(data)
# -1 表示异常,1 表示正常
n_outliers = np.sum(outlier_labels == -1)
print(f"LOF 检测到 {n_outliers} 个异常值")

我的经验:别急着删除异常值。我曾经发现一个"异常"点,后来验证发现是新的掺杂效应。先标记,再人工核查,最后决定去留。

4.5 知识体系总览

下面这张图,把数据采集与清洗的流程串起来了。你想想看,从数据库到实验台,每一步都有坑,但每一步也都有解法。

材料数据采集与清洗流程 公开数据库 Materials Project / OQMD 实验数据 纸质记录 / 电子表格 文献数据 PDF / 图片 / 表格 数据采集与数字化 API调用 / OCR识别 / 结构化录入 数据清洗 缺失值处理 删除 / 填充 / 预测 异常值检测 Z-score / LOF / 人工核查 数据标准化 归一化 / 编码转换 高质量结构化数据集 → 模型训练

数据采集与清洗,说白了就是"垃圾进,垃圾出"的反面。你花 80% 的时间做数据准备,剩下 20% 的时间建模,这才是正确的比例。我见过太多人急着调模型,结果数据一塌糊涂,最后白忙一场。

核心原则:数据质量决定模型上限。算法只是逼近这个上限的工具。

好了,这一章的内容就到这里。记住,好的数据是成功的一半。下次拿到新数据,先别急着跑模型,花点时间看看数据长什么样,值不值得信任。

专注资料整理