1. 矿物数据清洗的行业背景与挑战
矿物分类是地质勘探和资源评估中的基础性工作。在野外采集的原始矿物样本数据中,通常会混杂着各种干扰因素——来自不同矿层的样本可能因为采集工具磨损导致元素含量记录偏差,同一批次的实验室检测数据可能因为仪器校准问题出现系统性误差,甚至有些偏远地区的样本数据会因为运输条件限制而产生记录缺失。
我处理过的一个典型案例是某铜矿勘探项目的数据集:原始数据包含12种元素含量指标和8种物理特性参数,共计3200个样本。初步分析就发现了令人头疼的问题——近15%的样本存在不同程度的缺失值,铁元素含量指标中有明显的人为录入错误(将6.5%记录为65%),还有约8%的样本因检测条件限制导致部分参数异常偏低。
关键提示:矿物数据的异常往往具有领域特异性。例如在金银矿数据中,ppm级别的含量波动可能就值得关注,而在铁矿数据中,1%以下的含量变化可能只是检测误差。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 异常值检测的实战方法论
2.1 基于统计分布的离群点识别
对于连续型矿物特征(如元素含量百分比),我们首选用箱线图结合3σ原则进行初筛。以某钨矿项目的Mo元素数据为例:
python复制import numpy as np
from scipy import stats
# 计算Mo元素的Z-score
mo_data = df['Mo_content']
z_scores = np.abs(stats.zscore(mo_data))
outliers = np.where(z_scores > 3)
print(f"检测到{len(outliers[0])}个异常点,占比{len(outliers[0])/len(mo_data):.2%}")
但要注意,某些矿物元素本身就可能呈现重尾分布。我曾遇到过一个稀土矿数据集,其中Dy元素天然就符合帕累托分布,这时如果用正态假设去检测,会把真实的地质异常误判为数据错误。
2.2 基于领域知识的合理性校验
建立元素含量之间的约束规则是更可靠的方法。例如:
- 在铜矿石中,Cu含量与S含量通常存在正相关
- 稀土元素之间的比例应符合地壳丰度规律
- 密度测量值必须大于1g/cm³
我们开发了一套规则引擎来自动标记可疑样本:
python复制def validate_sample(row):
if row['Cu'] > 50 and row['S'] < 5: # 高铜低硫不合理
return False
if row['density'] < 1 or row['density'] > 20: # 密度超范围
return False
return True
df['is_valid'] = df.apply(validate_sample, axis=1)
3. 缺失值处理的策略选择
3.1 简单删除法的适用场景
当缺失率低于5%且随机分布时,直接删除是最佳选择。但要注意检查缺失模式——如果某台检测设备的样本全部缺失Fe含量,这种系统性缺失就不能简单删除。
3.2 高级填充技术对比
| 方法 | 适用场景 | 矿物数据案例 | 注意事项 |
|---|---|---|---|
| 均值填充 | 正态分布的小比例缺失 | 石英矿的SiO2含量 | 会压缩方差 |
| KNN填充 | 特征间相关性强的数据集 | 共生矿物的元素含量 | 计算量大 |
| 回归填充 | 存在强线性关系 | 主量元素与微量元素 | 需防止过拟合 |
| 多重插补 | 复杂缺失机制 | 多实验室合并数据 | 实现复杂 |
在某个银矿项目中,我们使用随机森林填充获得了最佳效果:
python复制from sklearn.ensemble import RandomForestRegressor
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
imputer = IterativeImputer(
estimator=RandomForestRegressor(n_estimators=100),
max_iter=10,
random_state=42
)
df_filled = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)
4. 数据标准化的技术细节
4.1 矿物特有的标准化挑战
不同于一般机器学习任务,矿物数据经常同时包含:
- 百分比尺度数据(如元素含量)
- ppm/ppb级微量元素数据
- 物理特性数据(密度、硬度等)
- 类别型数据(矿石类型、颜色等)
这要求我们采用混合标准化策略。我的经验法则是:
- 对主量元素(>1%)使用StandardScaler
- 对微量元素使用RobustScaler
- 物理特性参数视分布选择MinMax或Log变换
- 类别特征用独热编码
4.2 实战中的标准化流程
以某多金属矿数据为例:
python复制from sklearn.preprocessing import (
StandardScaler,
RobustScaler,
MinMaxScaler,
FunctionTransformer
)
from sklearn.compose import ColumnTransformer
# 定义不同特征的处理器
preprocessor = ColumnTransformer(
transformers=[
('major', StandardScaler(), ['SiO2','Al2O3','Fe2O3']),
('trace', RobustScaler(), ['Au_ppm','Ag_ppm']),
('physic', MinMaxScaler(), ['density','hardness']),
('log', FunctionTransformer(np.log1p), ['U_ppm']),
('cate', OneHotEncoder(), ['ore_type'])
])
重要经验:永远在训练集上fit_transform,在测试集上只transform。我曾因在全集上做标准化导致模型评估严重失真,这个错误让项目延误了两周。
5. 样本不平衡问题的解决方案
5.1 矿物数据中的类别失衡
在某个斑岩铜矿项目中,我们遇到的类别分布如下:
| 矿石类型 | 样本数 | 占比 |
|---|---|---|
| 高品位 | 120 | 3.75% |
| 中品位 | 800 | 25% |
| 低品位 | 2280 | 71.25% |
5.2 改进的SMOTE-ENN算法
传统SMOTE在矿物数据中容易生成不合理的合成样本。我们改进的方案是:
- 先使用SMOTE生成新样本
- 然后用ENN(Edited Nearest Neighbours)清理噪声
- 最后通过领域知识规则过滤
实现代码片段:
python复制from imblearn.combine import SMOTEENN
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import EditedNearestNeighbours
smote_enn = SMOTEENN(
smote=SMOTE(k_neighbors=5, sampling_strategy='minority'),
enn=EditedNearestNeighbours(n_neighbors=3),
random_state=42
)
X_res, y_res = smote_enn.fit_resample(X, y)
6. 完整数据清洗流水线构建
将上述步骤整合成可复用的Pipeline:
python复制from sklearn.pipeline import Pipeline
from sklearn.base import BaseEstimator, TransformerMixin
class DomainCleaner(BaseEstimator, TransformerMixin):
"""自定义领域知识清洗器"""
def __init__(self):
self.rules = {...}
def fit(self, X, y=None):
return self
def transform(self, X):
# 应用所有验证规则
return X.apply(validate_sample)
mineral_pipeline = Pipeline([
('cleaner', DomainCleaner()),
('imputer', IterativeImputer(...)),
('scaler', ColumnTransformer(...)),
('balancer', SMOTEENN(...))
])
这个管道在实际项目中帮我们节省了约70%的数据准备时间。关键是要保存所有转换器的参数,以便在新数据上应用完全相同的转换。
