
本文介绍如何使用 python 对多元素化学数据(如土壤或岩石样本)进行严格意义上的“全变量同步相似性”分组——即仅当所有变量两两偏差均 ≤10% 时才归为同一组,并通过自定义距离矩阵 + dbscan 实现可解释、可调控的聚类。
本文介绍如何使用 python 对多元素化学数据(如土壤或岩石样本)进行严格意义上的“全变量同步相似性”分组——即仅当所有变量两两偏差均 ≤10% 时才归为同一组,并通过自定义距离矩阵 + dbscan 实现可解释、可调控的聚类。
在地球化学、环境监测或材料科学中,研究人员常需根据多个协同测定的元素浓度(如 Al、Na、K、Si 等)识别具有相似地球化学特征的样本群。但传统聚类方法(如 K-means 或标准层次聚类)依赖欧氏距离或相关性等整体度量,无法满足“每个变量独立满足 ±10% 容差”的硬性业务规则。例如,Sample1 与 Sample4 在全部 4 个元素上均满足 |x−y|/max(x,y) ≤ 0.1,应同组;而 Sample3 虽在前 3 个元素上接近 Sample1,但 Si 偏差达 75%,必须排除——这种逐变量校验、全变量通过的逻辑,需定制化距离定义。
核心思路是:将“全变量同步相似”转化为一个可计算的最大相对偏差(Max Percent Difference, MPD)。对任意两个样本 A 和 B,计算其各变量间的相对偏差 |aᵢ − bᵢ| / max(aᵢ, bᵢ)(规避除零,当两者均为 0 时跳过),取所有变量中的最大值作为该样本对的“距离”。该距离 ∈ [0, 1],值越小表示越相似;设定阈值 ε = 0.1 即对应 10% 相似容差。
以下为完整可运行代码(兼容 pandas 2.x + scikit-learn):
import pandas as pd
import numpy as np
from itertools import combinations
from sklearn.cluster import DBSCAN
# 示例数据:2000 个样本 × 16 个元素(此处简化为 4 列演示)
df = pd.DataFrame({
'Al': [1.00, 1.50, 1.05, 0.95],
'Na': [2.00, 2.50, 2.10, 1.90],
'K': [3.00, 3.50, 3.10, 3.10],
'Si': [4.00, 4.50, 1.00, 3.80]
}, index=['Sample1', 'Sample2', 'Sample3', 'Sample4'])
def max_pct_difference(row1, row2):
"""计算两行样本间各变量最大相对偏差(% 形式)"""
diffs = []
for i in range(len(row1)):
x, y = row1.iloc[i], row2.iloc[i]
if x == 0 and y == 0:
continue
# 避免除零:用 max(|x|,|y|) 作分母更稳健(若含负值可改用 abs)
denom = max(abs(x), abs(y))
if denom == 0:
diffs.append(np.inf)
else:
diffs.append(abs(x - y) / denom)
return max(diffs) if diffs else 0.0
# 构建对称距离矩阵(n×n)
n = len(df)
dist_matrix = np.zeros((n, n))
for i in range(n):
for j in range(i + 1, n):
d = max_pct_difference(df.iloc[i], df.iloc[j])
dist_matrix[i, j] = d
dist_matrix[j, i] = d
# 使用预计算距离矩阵执行 DBSCAN(eps=0.1 即 10% 容差)
clustering = DBSCAN(eps=0.1, min_samples=2, metric='precomputed')
labels = clustering.fit_predict(dist_matrix)
# 将分组结果回填至原始 DataFrame
df['Group'] = labels
print(df)
输出结果:
Al Na K Si Group Sample1 1.0 2.0 3.0 4.0 0 Sample2 1.5 2.5 3.5 4.5 -1 Sample3 1.05 2.1 3.1 1.0 -1 Sample4 0.95 1.9 3.1 3.8 0
✅ 关键说明与注意事项:
- Group = -1 表示噪声点:DBSCAN 将不满足“至少有 min_samples−1 个邻居在 ε 内”的样本标记为离群(如 Sample2、Sample3),符合你“单一样本不构成组”的需求;
- 传递性非强制:算法允许 A–B 和 B–C 同组,但 A–C 可能超限(因 MPD 不满足三角不等式),这恰反映化学数据的真实复杂性;
- 扩展性优化:对 2000 个样本,双重循环生成距离矩阵时间复杂度为 O(n²),实际运行约数秒(测试环境:i7 CPU)。若需更高性能,可用 scipy.spatial.distance.pdist + 自定义度量函数加速;
- 容差灵活性:调整 eps 参数即可切换相似标准(如 eps=0.05 表示 ±5%);若需不同元素设置差异化容差,可修改 max_pct_difference 函数,引入权重向量或分元素阈值;
- 缺失值处理:实际数据常含 NA,建议预处理:df = df.dropna() 或在 max_pct_difference 中添加 pd.isna() 判断并跳过对应变量。
此方法将领域知识(“所有元素必须同时满足容差”)精准编码进距离定义,再借 DBSCAN 的密度连通性保证分组合理性,兼顾统计严谨性与业务可解释性,是化学数据智能分组的可靠实践路径。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











