You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Scipy的Mahalanobis距离实现检测DataFrame中的异常值?

用Scipy实现DataFrame全局马氏距离异常值检测

核心逻辑

Scipy的mahalanobis函数仅支持两个一维向量的距离计算,要处理整个DataFrame,只需将每行数据作为单个向量,与数据集的全局均值向量计算距离,再结合卡方分布推导p值来判定异常。

完整实现代码

1. 导入依赖

import pandas as pd
import numpy as np
from scipy.spatial.distance import mahalanobis
from scipy.stats import chi2

2. 准备测试数据

# 生成模拟多维数据集
np.random.seed(42)
df = pd.DataFrame({
    'feat1': np.random.normal(50, 10, 100),
    'feat2': np.random.normal(20, 5, 100),
    'feat3': np.random.normal(10, 2, 100)
})
# 手动插入2个异常值
df.loc[100] = [100, 50, 20]
df.loc[101] = [0, 0, 0]

3. 计算全局统计量

# 提取均值向量
mean_vec = df.mean().values
# 计算协方差矩阵,加微小正则项避免奇异矩阵
cov_mat = df.cov().values + 1e-6 * np.eye(df.shape[1])
# 求协方差矩阵的逆矩阵
inv_cov = np.linalg.inv(cov_mat)

4. 批量计算马氏距离与p值

def get_mahalanobis_stats(row):
    row_vec = row.values
    # 调用Scipy的mahalanobis函数计算距离
    dist = mahalanobis(row_vec, mean_vec, inv_cov)
    # 马氏距离平方服从卡方分布,自由度为特征数-1
    chi_sq = dist ** 2
    # 计算右侧检验的p值
    p_val = 1 - chi2.cdf(chi_sq, df=df.shape[1]-1)
    return pd.Series([dist, chi_sq, p_val], index=['mahalanobis_dist', 'chi_sq', 'p_value'])

# 应用到DataFrame每一行
stats_df = df.apply(get_mahalanobis_stats, axis=1)
# 合并原数据与统计结果
final_df = pd.concat([df, stats_df], axis=1)

5. 标记异常值

# 以p<0.05为阈值标记异常值,可根据业务调整
final_df['is_outlier'] = final_df['p_value'] < 0.05

关键细节

  • 协方差矩阵添加1e-6 * np.eye()是为了避免数据线性相关时出现奇异矩阵,导致逆矩阵无法求解
  • 卡方分布的自由度为特征数量-1,这是p值计算的核心前提
  • 异常值阈值可灵活调整,比如业务对异常敏感时可设为0.01

内容的提问来源于stack exchange,提问作者kp42

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:52:34