如何在散点图/Pandas DataFrame中更科学地识别异常值?
二维数据异常值识别的优化方案
1. 基于马氏距离(Mahalanobis Distance)的方法
马氏距离能自动考虑变量间的相关性,比单纯分位数方法更严谨,可识别偏离数据整体分布的点,不管是单维度还是联合维度的异常。
原理
马氏距离衡量样本点到数据中心的距离,同时消除变量间的尺度和相关性影响,公式为:
$D^2 = (x - \mu)^T \Sigma^{-1} (x - \mu)$
其中$\mu$是均值向量,$\Sigma$是协方差矩阵。距离超过卡方分布对应分位数的点判定为异常值(自由度为2时,99%置信度对应阈值约为9.21)。
代码实现
import numpy as np import pandas as pd from scipy.spatial.distance import mahalanobis # 计算均值和协方差矩阵 mean = df[['x', 'y']].mean() cov = df[['x', 'y']].cov() inv_cov = np.linalg.inv(cov) # 计算每个点的马氏距离平方 df['mahalanobis_dist_sq'] = df.apply( lambda row: mahalanobis(row[['x', 'y']], mean, inv_cov)**2, axis=1 ) # 设置阈值(自由度2,99%置信度) threshold = 9.21 outliers = df[df['mahalanobis_dist_sq'] > threshold]
优势
- 自动关联x和y的相关性,无需手动设置多个分位数参数
- 基于卡方分布确定阈值,数学严谨性强
- 不受数据尺度变化影响
2. 局部离群因子(LOF, Local Outlier Factor)
LOF是基于密度的方法,专门识别局部稀疏区域的点——哪怕这些点在全局分布中不算极端,完美匹配你“仅标注非密集聚集点”的需求。
原理
计算每个点的局部密度与邻域点密度的比值,比值大于1说明该点密度远低于周围点,判定为异常。可通过调整邻域大小(n_neighbors)定义“密集”的标准。
代码实现
from sklearn.neighbors import LocalOutlierFactor # 初始化LOF模型,n_neighbors建议设为数据规模的1-5% lof = LocalOutlierFactor(n_neighbors=50, contamination=0.01) # 拟合数据,1为正常点,-1为异常点 df['lof_outlier'] = lof.fit_predict(df[['x', 'y']]) outliers = df[df['lof_outlier'] == -1]
优势
- 精准定位局部稀疏的异常点,完全贴合你的核心需求
- 仅需调整邻域大小和异常比例两个参数,无需手动设置分位数
- 适配任意形状的数据分布,不依赖高斯分布假设
3. 孤立森林(Isolation Forest)
孤立森林是基于树结构的异常检测算法,适合处理大规模数据(数千个点完全适用),效率高且无分布假设。
原理
通过随机划分特征空间,异常点会被更快孤立出来,平均路径长度更短,以此判断是否为异常。
代码实现
from sklearn.ensemble import IsolationForest # 初始化孤立森林模型,contamination指定异常点比例 iso_forest = IsolationForest(contamination=0.01, random_state=42) df['iso_outlier'] = iso_forest.fit_predict(df[['x', 'y']]) outliers = df[df['iso_outlier'] == -1]
优势
- 处理大规模数据速度快,适配你的数据规模
- 无分布假设,对各类数据适应性强
- 参数少,仅需设置异常比例即可
方案选择建议
- 若数据近似服从高斯分布,马氏距离是最严谨的统计方案,调参成本低
- 若核心需求是标注“非密集聚集”的局部异常,LOF是最优选择
- 若追求处理速度和通用性,孤立森林适合大规模数据场景
以上方法均无需手动设置多个分位数参数,结果更均衡,且具备更强的数学严谨性。
内容的提问来源于stack exchange,提问作者am1234
相关产品推荐
相关产品推荐

