1. 项目概述
"矿物分类实战(一):从异常值到标准化——数据清洗全流程拆解"这个标题直指数据科学项目中最关键也最容易被忽视的环节——数据预处理。在实际工作中,我们常花费80%的时间在数据清洗上,而真正建模可能只占20%。这个系列的第一部分将完整呈现我从原始矿物数据到建模就绪数据的全流程处理方法。
矿物数据具有典型的工业数据集特征:多源异构、量纲不一、缺失严重、异常值多。我曾处理过一个铜矿品位数据集,原始数据中砷含量字段的异常值高达37%,直接建模会导致模型完全失效。通过系统化的数据清洗流程,我们最终将数据质量提升到可接受水平,模型准确率提高了42个百分点。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心需求解析
2.1 矿物数据的特殊性
矿物数据通常来自实验室检测、现场传感器和人工记录三个渠道。实验室数据精度高但样本少,传感器数据量大但噪声多,人工记录易出现录入错误。某铁矿项目的原始数据中,仅单位不统一就发现了"g/t"、"ppm"、"百分比"三种表达方式共存的情况。
2.2 清洗流程的必要性
未经清洗的矿物数据会导致:
- 异常值扭曲统计分布(如某个品位值误录为100倍实际值)
- 量纲差异使模型偏向大数值特征(如SiO2含量以%计,而Au含量以g/t计)
- 缺失值导致样本利用率低下(直接删除可能损失过半数据)
3. 数据清洗全流程详解
3.1 异常值检测与处理
3.1.1 基于统计的方法
对于正态分布特征,我常用3σ原则:
python复制def remove_outliers_3sigma(df, col):
mean = df[col].mean()
std = df[col].std()
return df[(df[col] > mean-3*std) & (df[col] < mean+3*std)]
但对矿物数据更适用的是箱线图法(IQR),特别是对于偏态分布的元素含量:
python复制Q1 = df[col].quantile(0.25)
Q3 = df[col].quantile(0.75)
IQR = Q3 - Q1
df = df[~((df[col] < (Q1 - 1.5*IQR)) | (df[col] > (Q3 + 1.5*IQR)))]
注意:矿物数据中的"异常值"可能是真实的高品位区,需结合地质知识判断。我曾在一个金矿项目中保留了被统计方法判定为异常值的样本,后来证实是重要的矿化异常。
3.1.2 基于距离的方法
当特征间存在相关性时,使用马氏距离更有效:
python复制from scipy.spatial.distance import mahalanobis
cov = df.cov().values
inv_cov = np.linalg.inv(cov)
df['mahalanobis'] = df.apply(lambda x: mahalanobis(x, df.mean(), inv_cov), axis=1)
3.2 缺失值处理
3.2.1 删除策略
- 整列删除:当某特征缺失率>60%(如某微量元素检测限过高)
- 整行删除:当关键特征缺失(如主元素含量缺失)
3.2.2 填充策略
- 均值/中位数填充:适合正态/偏态分布的连续变量
- KNN填充:考虑特征相关性(需先标准化)
python复制from sklearn.impute import KNNImputer
imputer = KNNImputer(n_neighbors=5)
df_filled = imputer.fit_transform(df)
- 地质约束填充:如某钻孔的Al2O3含量可用相邻样品的地质统计学变差函数估算
3.3 数据标准化
3.3.1 Z-score标准化
python复制from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df)
3.3.2 Robust Scaling
对含异常值的数据更鲁棒:
python复制from sklearn.preprocessing import RobustScaler
robust_scaler = RobustScaler()
df_robust = robust_scaler.fit_transform(df)
3.3.3 矿物数据特有的对数变换
对金、银等服从对数正态分布的元素:
python复制df['Au_log'] = np.log1p(df['Au'])
4. 类别不平衡处理
4.1 SMOTE过采样
针对稀有矿物类别(如某矿床中的铂族元素):
python复制from imblearn.over_sampling import SMOTE
sm = SMOTE(k_neighbors=3)
X_res, y_res = sm.fit_resample(X, y)
4.2 欠采样策略
对优势矿物类别随机降采样,但会损失信息。我常用Tomek Links方法:
python复制from imblearn.under_sampling import TomekLinks
tl = TomekLinks()
X_res, y_res = tl.fit_resample(X, y)
5. 完整Pipeline构建
将上述步骤整合为可复用的处理流程:
python复制from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
preprocessor = ColumnTransformer(
transformers=[
('num', Pipeline([
('imputer', KNNImputer(n_neighbors=5)),
('scaler', RobustScaler())
]), numerical_cols),
('log', Pipeline([
('imputer', KNNImputer(n_neighbors=3)),
('transformer', FunctionTransformer(np.log1p))
]), lognormal_cols)
])
full_pipeline = Pipeline([
('preprocessor', preprocessor),
('smote', SMOTE(k_neighbors=3))
])
6. 实战经验分享
-
保存中间结果:每次清洗步骤后保存副本,方便回溯。我曾因未保存原始数据导致无法验证某个异常值的真实性。
-
可视化验证:在每步处理后用pairplot检查数据分布变化:
python复制import seaborn as sns
sns.pairplot(df[['SiO2','Al2O3','Fe2O3']])
-
领域知识优先:某铅锌矿项目中,统计显示Zn/Pb比值异常,但地质工程师确认这是典型的矿化分带特征,应保留。
-
处理顺序很重要:应先处理异常值再填充缺失值,否则异常值会影响填充结果。某次我将顺序弄反,导致填充值被异常值拉偏。
-
内存优化技巧:对大型矿物数据集(如数万钻孔样本),使用dtype优化可节省70%内存:
python复制df = df.astype({'SiO2':'float32', 'Au':'float32'})
这套流程在某铜钼矿品位预测项目中,将模型AUC从0.61提升到了0.89。数据质量决定模型上限,好的特征工程可以弥补算法选择的不足。下一期我们将探讨矿物数据的特征构造方法,包括地质统计学变差函数的应用。
