"距离不仅仅是直线的长度,更要考虑方向的重要性。"
"Distance is not just the length of a straight line, but also the importance of direction."
—— 普拉桑塔·钱德拉·马哈拉诺比斯 (Prasanta Chandra Mahalanobis) | 印度统计学家 | 1893 ~ 1972
🐍Python工具箱
numpy.linalg.inv()矩阵求逆
numpy.dot()矩阵乘法
scipy.spatial.distance.mahalanobis()计算马氏距离
matplotlib.pyplot.contour()等高线图
numpy.cov()协方差矩阵
scipy.stats.chi2()卡方分布
本章概览
🎯 核心内容
- • 欧氏距离的局限性
- • 马氏距离的定义
- • 几何直观理解
- • 标准化与相关性
- • 实际应用场景
📐 关键概念
- • 协方差矩阵 Σ
- • D² = (x-μ)ᵀΣ⁻¹(x-μ)
- • 标准化马氏距离
- • 等距离椭圆
- • 异常值检测
23.1
从欧氏距离到马氏距离
From Euclidean to Mahalanobis Distance
在数据分析中,我们经常需要衡量两点之间的距离。 最常用的是欧氏距离,但它有一个致命的缺陷:没有考虑数据的分布特性。 本节将介绍一种更智能的距离度量——马氏距离。
📏 回顾:欧氏距离
欧氏距离是我们最熟悉的距离概念,也称为"直线距离"。
二维欧氏距离
d = √[(x₁-y₁)² + (x₂-y₂)²]
公式(1):二维空间中两点的欧氏距离
d维欧氏距离
d = √[Σᵢ(xᵢ-yᵢ)²] = √[(x-y)ᵀ(x-y)]
公式(2):高维空间的推广形式
✅ 优点
• 直观易懂
• 计算简单
• 几何意义明确
• 符合日常经验
• 计算简单
• 几何意义明确
• 符合日常经验
⚠️ 局限
• 假设各维度同等重要
• 忽略变量间的相关性
• 受量纲影响大
• 不考虑数据分布
• 忽略变量间的相关性
• 受量纲影响大
• 不考虑数据分布
🤔 思考
假设有两个特征:身高(单位cm)和体重(单位kg)。
点A=(170cm, 60kg),点B=(171cm, 80kg),点C=(190cm, 61kg)
哪个点离A更"近"?欧氏距离给出的答案合理吗?
点A=(170cm, 60kg),点B=(171cm, 80kg),点C=(190cm, 61kg)
哪个点离A更"近"?欧氏距离给出的答案合理吗?
🚨 欧氏距离的问题
让我们通过几个具体例子来看欧氏距离的局限性。
⚖️
问题1:量纲不一致
场景:比较房屋
• 特征1:面积(10-200 m²)
• 特征2:卧室数(1-5个)
• 特征1:面积(10-200 m²)
• 特征2:卧室数(1-5个)
问题:
面积的数值范围远大于卧室数,
导致距离计算主要由面积主导
面积的数值范围远大于卧室数,
导致距离计算主要由面积主导
结果:卧室数的差异被"淹没"
📊
问题2:方差不同
场景:学生成绩
• 数学:均值70,标准差20
• 英语:均值70,标准差5
• 数学:均值70,标准差20
• 英语:均值70,标准差5
问题:
数学分数波动大,英语分数波动小,
但欧氏距离对两者一视同仁
数学分数波动大,英语分数波动小,
但欧氏距离对两者一视同仁
结果:数学差1分 ≠ 英语差1分
🔗
问题3:忽略相关性
场景:鸢尾花
• 花萼长度和花萼宽度
• 这两个特征高度相关
• 花萼长度和花萼宽度
• 这两个特征高度相关
问题:
两个特征沿某个方向变化时,
欧氏距离没有考虑这种相关性
两个特征沿某个方向变化时,
欧氏距离没有考虑这种相关性
结果:同样的欧氏距离,
沿相关方向和垂直方向的意义不同
沿相关方向和垂直方向的意义不同
💡 核心问题
欧氏距离假设所有方向同等重要,
但实际数据往往有不同的方差和相关性!
我们需要一种能够自动适应数据分布的距离度量。
但实际数据往往有不同的方差和相关性!
我们需要一种能够自动适应数据分布的距离度量。
✨ 马氏距离:智能的距离度量
马氏距离(Mahalanobis Distance)由印度统计学家P.C. Mahalanobis在1936年提出, 它巧妙地解决了欧氏距离的所有问题。
马氏距离定义
D²(x, μ) = (x - μ)ᵀ Σ⁻¹ (x - μ)
公式(3):点x到分布中心μ的马氏距离的平方
x:数据点
(d维向量)
(d维向量)
μ:分布中心
(均值向量)
(均值向量)
Σ:协方差矩阵
(d×d矩阵)
(d×d矩阵)
两点间的马氏距离
D²(x, y) = (x - y)ᵀ Σ⁻¹ (x - y)
公式(4):点x到点y的马氏距离(基于分布Σ)
✅ 神奇之处
1. 自动标准化
Σ⁻¹考虑了各维度的方差
Σ⁻¹考虑了各维度的方差
2. 去相关性
Σ⁻¹去除了变量间的相关性
Σ⁻¹去除了变量间的相关性
3. 量纲无关
自动适应不同的量纲
自动适应不同的量纲
🎯 特殊情况
如果Σ = I
(单位矩阵)
马氏距离 = 欧氏距离
(单位矩阵)
马氏距离 = 欧氏距离
如果Σ是对角矩阵
马氏距离 = 标准化欧氏距离
马氏距离 = 标准化欧氏距离
💡 直观理解
想象数据分布是一个椭圆形云团:
• 欧氏距离:用圆形测量距离(各方向平等)
• 马氏距离:用椭圆测量距离(沿主轴方向拉伸/压缩)
马氏距离把椭圆"拉"成圆,让距离更合理!
• 欧氏距离:用圆形测量距离(各方向平等)
• 马氏距离:用椭圆测量距离(沿主轴方向拉伸/压缩)
马氏距离把椭圆"拉"成圆,让距离更合理!
🔢 马氏距离的计算步骤
让我们通过一个简单的二维例子,逐步计算马氏距离。
示例数据
数据点:x = [3, 4]ᵀ
分布中心:μ = [1, 2]ᵀ
协方差矩阵:Σ = [[2, 1], [1, 2]]
1
计算差值向量
Δ = x - μ = [3-1, 4-2]ᵀ = [2, 2]ᵀ
2
计算协方差矩阵的逆
Σ⁻¹ = [[2, 1], [1, 2]]⁻¹
= (1/3) × [[2, -1], [-1, 2]]
= [[2/3, -1/3], [-1/3, 2/3]]
= (1/3) × [[2, -1], [-1, 2]]
= [[2/3, -1/3], [-1/3, 2/3]]
3
计算中间结果
Σ⁻¹Δ = [[2/3, -1/3], [-1/3, 2/3]] × [2, 2]ᵀ
= [2/3×2 - 1/3×2, -1/3×2 + 2/3×2]ᵀ
= [2/3, 2/3]ᵀ
= [2/3×2 - 1/3×2, -1/3×2 + 2/3×2]ᵀ
= [2/3, 2/3]ᵀ
4
计算最终距离
D² = Δᵀ Σ⁻¹ Δ
= [2, 2] × [2/3, 2/3]ᵀ
= 2×2/3 + 2×2/3
= 8/3 ≈ 2.67
= [2, 2] × [2/3, 2/3]ᵀ
= 2×2/3 + 2×2/3
= 8/3 ≈ 2.67
D = √(8/3) ≈ 1.63
📊 对比
欧氏距离:
d = √(2² + 2²) = √8 ≈ 2.83
d = √(2² + 2²) = √8 ≈ 2.83
马氏距离:
D ≈ 1.63
D ≈ 1.63
马氏距离更小,因为考虑了相关性!
🎨 几何直观理解
马氏距离的几何意义可以通过等距离曲线来理解。
欧氏距离
等距离曲线:圆
所有方向的距离增长速度相同
所有方向的距离增长速度相同
公式:
(x-μ₁)² + (x-μ₂)² = r²
(x-μ₁)² + (x-μ₂)² = r²
特点:
• 各向同性(isotropic)
• 不考虑数据的椭圆形状
• 各向同性(isotropic)
• 不考虑数据的椭圆形状
马氏距离
等距离曲线:椭圆
根据数据分布自动调整形状
根据数据分布自动调整形状
公式:
(x-μ)ᵀ Σ⁻¹ (x-μ) = r²
(x-μ)ᵀ Σ⁻¹ (x-μ) = r²
特点:
• 各向异性(anisotropic)
• 椭圆的形状和方向由Σ决定
• 各向异性(anisotropic)
• 椭圆的形状和方向由Σ决定
🔑 关键洞察
1. 椭圆的长轴和短轴
• 长轴:数据方差大的方向
• 短轴:数据方差小的方向
• 马氏距离在长轴方向"宽松",短轴方向"严格"
• 长轴:数据方差大的方向
• 短轴:数据方差小的方向
• 马氏距离在长轴方向"宽松",短轴方向"严格"
2. 标准化效果
马氏距离 = 标准化后的欧氏距离
相当于先把椭圆"拉"成圆,再计算欧氏距离
马氏距离 = 标准化后的欧氏距离
相当于先把椭圆"拉"成圆,再计算欧氏距离
3. 概率解释
对于多元正态分布,等马氏距离曲线 = 等概率密度曲线
马氏距离相同 → 概率密度相同
对于多元正态分布,等马氏距离曲线 = 等概率密度曲线
马氏距离相同 → 概率密度相同
📋 马氏距离的性质
✅
性质1:非负性
D²(x, μ) ≥ 0,且 D²(x, μ) = 0 当且仅当 x = μ
✅
性质2:对称性
D(x, y) = D(y, x)
(如果使用相同的协方差矩阵)
(如果使用相同的协方差矩阵)
✅
性质3:尺度不变性
马氏距离不受量纲变化影响
(因为Σ自动考虑了各维度的尺度)
(因为Σ自动考虑了各维度的尺度)
✅
性质4:线性变换不变性
对数据进行线性变换后,
马氏距离保持相对关系不变
马氏距离保持相对关系不变
✅
性质5:卡方分布
如果x ~ N(μ, Σ),则 D²(x, μ) ~ χ²(d)
(d是维度,这是异常值检测的理论基础)
(d是维度,这是异常值检测的理论基础)
💡 实践意义
这些性质使得马氏距离在异常值检测、聚类分析、
分类算法等领域有广泛应用。
分类算法等领域有广泛应用。
🎯 23.1 关键要点
欧氏距离局限
• 量纲不一致
• 方差不同
• 忽略相关性
• 不考虑分布
• 方差不同
• 忽略相关性
• 不考虑分布
马氏距离
• D² = ΔᵀΣ⁻¹Δ
• 自动标准化
• 去相关性
• 量纲无关
• 自动标准化
• 去相关性
• 量纲无关
几何理解
• 等距离椭圆
• 椭圆→圆变换
• 概率密度等高线
• 各向异性
• 椭圆→圆变换
• 概率密度等高线
• 各向异性
💡 核心洞察
• 智能距离:马氏距离能自动适应数据的分布特性
• 椭圆视角:把椭圆形数据云"拉"成圆,再测量距离
• Σ⁻¹的威力:协方差矩阵的逆包含了所有分布信息
• 标准化本质:马氏距离 = 标准化后的欧氏距离
• 下一步:学习马氏距离的实际应用(23.2-23.3)
• 椭圆视角:把椭圆形数据云"拉"成圆,再测量距离
• Σ⁻¹的威力:协方差矩阵的逆包含了所有分布信息
• 标准化本质:马氏距离 = 标准化后的欧氏距离
• 下一步:学习马氏距离的实际应用(23.2-23.3)
✦
23.2
马氏距离的应用
Applications of Mahalanobis Distance
在23.1节中,我们学习了马氏距离的定义和性质。 本节将探讨马氏距离的实际应用, 包括异常值检测、分类算法、聚类分析等。
🎯 应用1:异常值检测
异常值检测是马氏距离最重要的应用之一,用于识别数据中的"离群点"。
基本思想
正常数据点应该靠近分布中心,
异常值会有较大的马氏距离
异常值会有较大的马氏距离
如果 D²(x, μ) > threshold
→ x 是异常值
→ x 是异常值
理论基础:卡方分布
前提:数据服从多元正态分布 x ~ N(μ, Σ)
D²(x, μ) ~ χ²(d)
阈值设置:
• 95%置信度:χ²₀.₀₅(d)
• 99%置信度:χ²₀.₀₁(d)
• 99.9%置信度:χ²₀.₀₀₁(d)
• 95%置信度:χ²₀.₀₅(d)
• 99%置信度:χ²₀.₀₁(d)
• 99.9%置信度:χ²₀.₀₀₁(d)
例如:d=2时
• 95%:χ²₀.₀₅(2) ≈ 5.99
• 99%:χ²₀.₀₁(2) ≈ 9.21
• 95%:χ²₀.₀₅(2) ≈ 5.99
• 99%:χ²₀.₀₁(2) ≈ 9.21
✅ 优势
• 考虑相关性:能识别在相关方向上的异常
• 自动标准化:不受量纲影响
• 多维有效:适用于高维数据
• 统计理论:有明确的概率阈值
• 自动标准化:不受量纲影响
• 多维有效:适用于高维数据
• 统计理论:有明确的概率阈值
📊 实例:鸢尾花数据
场景:检测鸢尾花测量数据中的异常值
步骤:
1. 计算各类别的均值μ和协方差Σ
2. 对每个样本计算D²(x, μ)
3. 设置阈值(如χ²₀.₀₅(4) ≈ 9.49)
4. 标记D² > 9.49的样本为异常值
1. 计算各类别的均值μ和协方差Σ
2. 对每个样本计算D²(x, μ)
3. 设置阈值(如χ²₀.₀₅(4) ≈ 9.49)
4. 标记D² > 9.49的样本为异常值
结果:可以识别出测量错误或罕见变种
⚠️ 注意事项
1. 正态性假设:数据应近似正态分布
2. 样本量:需要足够样本估计Σ(至少n > d)
3. 异常值影响:异常值会影响μ和Σ的估计
解决:使用稳健估计(如MCD)
解决:使用稳健估计(如MCD)
🎯 应用2:分类算法
马氏距离可以用于基于距离的分类,特别是在贝叶斯分类中。
最小马氏距离分类器
思想:
将新样本x分类到马氏距离最小的类别
将新样本x分类到马氏距离最小的类别
ŷ = argmink D²(x, μk)
= argmink (x-μk)ᵀ Σk⁻¹ (x-μk)
= argmink (x-μk)ᵀ Σk⁻¹ (x-μk)
与贝叶斯分类的关系
假设:每类数据服从正态分布 N(μk, Σk)
对数似然:
log p(x|Ck) = -½D²(x,μk) - ½log|Σk| - 常数
log p(x|Ck) = -½D²(x,μk) - ½log|Σk| - 常数
特殊情况:如果Σk=Σ(协方差相同)
最小马氏距离 = 最大后验概率(MAP)
最小马氏距离 = 最大后验概率(MAP)
✅ 优势
• 自动考虑类别形状
• 处理不同方差的类
• 理论基础坚实
• 计算相对简单
• 处理不同方差的类
• 理论基础坚实
• 计算相对简单
⚠️ 局限
• 假设正态分布
• 需要估计Σk(可能不稳定)
• 计算Σ⁻¹成本高
• 样本量要求
• 需要估计Σk(可能不稳定)
• 计算Σ⁻¹成本高
• 样本量要求
🔬 实践应用
医疗诊断:根据多个指标分类疾病类型
人脸识别:基于面部特征向量的身份识别
质量控制:判断产品是否合格
🎯 应用3:聚类分析
在聚类中,马氏距离可以更好地识别椭圆形簇。
马氏距离聚类
思想:
使用马氏距离代替欧氏距离进行聚类
使用马氏距离代替欧氏距离进行聚类
常见算法:
• K-means with Mahalanobis distance
• 高斯混合模型(GMM)
• 层次聚类(Ward方法)
• K-means with Mahalanobis distance
• 高斯混合模型(GMM)
• 层次聚类(Ward方法)
高斯混合模型(GMM)
模型:
每个簇是一个高斯分布 N(μk, Σk)
每个簇是一个高斯分布 N(μk, Σk)
距离度量:
自然使用马氏距离D²(x, μk)
自然使用马氏距离D²(x, μk)
优势:
• 可以发现不同形状、大小、方向的簇
• 软聚类:给出概率分配
• EM算法保证收敛
• 可以发现不同形状、大小、方向的簇
• 软聚类:给出概率分配
• EM算法保证收敛
📊 对比:欧氏 vs 马氏
欧氏距离聚类:
倾向于找到圆形簇
倾向于找到圆形簇
马氏距离聚类:
可以找到椭圆形簇
可以找到椭圆形簇
🎯 适用场景
• 簇的形状不规则
• 不同簇方差不同
• 变量间有相关性
💡 实践提示
• 初始化:用K-means初始化GMM
• 正则化:添加小量到Σ对角线防止奇异
• 模型选择:用BIC或AIC选择簇数
• 可视化:绘制等马氏距离椭圆
• 正则化:添加小量到Σ对角线防止奇异
• 模型选择:用BIC或AIC选择簇数
• 可视化:绘制等马氏距离椭圆
🎯 应用4:特征选择与降维
马氏距离可以帮助评估特征的重要性和冗余性。
📏
特征重要性评估
思想:
移除某个特征后,类别间的马氏距离变化
移除某个特征后,类别间的马氏距离变化
度量:
• 特征i重要 → 移除后距离显著减小
• 特征i不重要 → 移除后距离变化小
• 特征i重要 → 移除后距离显著减小
• 特征i不重要 → 移除后距离变化小
🔗
冗余特征识别
思想:
两个特征高度相关 → Σ中相关系数大
两个特征高度相关 → Σ中相关系数大
策略:
• 检查Σ的非对角元素
• 移除冗余特征,保留代表性特征
• 检查Σ的非对角元素
• 移除冗余特征,保留代表性特征
📉
与PCA的关系
联系:
PCA找到的主成分方向 = Σ的特征向量
PCA找到的主成分方向 = Σ的特征向量
马氏距离视角:
• 保留主成分 = 保留方差大的方向
• 等价于在主成分空间中计算距离
• 保留主成分 = 保留方差大的方向
• 等价于在主成分空间中计算距离
🎯 应用5:其他重要应用
🔍
图像匹配
• 计算图像特征向量间的距离
• 考虑特征的协方差结构
• 提高匹配准确性
• 考虑特征的协方差结构
• 提高匹配准确性
📊
时间序列分析
• 比较多变量时间序列
• 考虑变量间的相关性
• 异常模式检测
• 考虑变量间的相关性
• 异常模式检测
🎯
推荐系统
• 计算用户/物品相似度
• 考虑特征的分布特性
• 个性化推荐
• 考虑特征的分布特性
• 个性化推荐
🏥
生物信息学
• 基因表达数据分析
• 识别差异表达基因
• 样本分类
• 识别差异表达基因
• 样本分类
🌐
入侵检测
• 网络流量异常检测
• 多维特征空间
• 实时监控
• 多维特征空间
• 实时监控
📈
金融风险
• 投资组合风险评估
• 信用评分
• 欺诈检测
• 信用评分
• 欺诈检测
💻 实践:Python实现
让我们看看如何在Python中使用马氏距离。
基础实现
import numpy as np
from scipy.spatial.distance import mahalanobis
from scipy.stats import chi2
# 1. 计算马氏距离
def compute_mahalanobis(x, mean, cov):
"""
x: 数据点 (d维)
mean: 均值向量 (d维)
cov: 协方差矩阵 (d×d)
"""
inv_cov = np.linalg.inv(cov)
diff = x - mean
dist_sq = np.dot(np.dot(diff, inv_cov), diff)
return np.sqrt(dist_sq)
# 或使用scipy
dist = mahalanobis(x, mean, np.linalg.inv(cov))异常值检测
# 2. 异常值检测
def detect_outliers(X, alpha=0.05):
"""
X: 数据矩阵 (n×d)
alpha: 显著性水平
"""
n, d = X.shape
mean = np.mean(X, axis=0)
cov = np.cov(X.T)
inv_cov = np.linalg.inv(cov)
# 计算每个点的马氏距离平方
distances = []
for i in range(n):
diff = X[i] - mean
dist_sq = np.dot(np.dot(diff, inv_cov), diff)
distances.append(dist_sq)
# 卡方分布阈值
threshold = chi2.ppf(1-alpha, df=d)
# 标记异常值
outliers = np.array(distances) > threshold
return outliers, distances分类应用
# 3. 最小马氏距离分类
def mahalanobis_classifier(x, means, covs):
"""
x: 新样本
means: 各类别的均值 [μ₁, μ₂, ...]
covs: 各类别的协方差 [Σ₁, Σ₂, ...]
"""
distances = []
for mean, cov in zip(means, covs):
dist = compute_mahalanobis(x, mean, cov)
distances.append(dist)
return np.argmin(distances) # 返回最近类别💡 实用技巧
• 数值稳定性:使用np.linalg.lstsq代替直接求逆
• 正则化:cov + λI 防止奇异矩阵
• 高维数据:考虑使用收缩估计(shrinkage)
• 大数据:使用增量算法或采样
• 正则化:cov + λI 防止奇异矩阵
• 高维数据:考虑使用收缩估计(shrinkage)
• 大数据:使用增量算法或采样
📊 总结:何时使用马氏距离?
✅ 推荐使用
数据特征
• 变量间有相关性
• 不同变量方差差异大
• 量纲不一致
• 数据近似正态分布
• 不同变量方差差异大
• 量纲不一致
• 数据近似正态分布
应用场景
• 异常值检测
• 多元正态分类
• 椭圆形簇聚类
• 需要统计理论支撑
• 多元正态分类
• 椭圆形簇聚类
• 需要统计理论支撑
⚠️ 谨慎使用
数据特征
• 样本量小(n < d)
• 非正态分布
• 协方差矩阵奇异
• 存在大量异常值
• 非正态分布
• 协方差矩阵奇异
• 存在大量异常值
其他情况
• 计算资源有限(Σ⁻¹昂贵)
• 实时系统(速度要求高)
• 简单数据(欧氏距离足够)
• 无法估计Σ
• 实时系统(速度要求高)
• 简单数据(欧氏距离足够)
• 无法估计Σ
🎯 决策建议
如果数据有明显的协方差结构且样本量充足,
马氏距离通常比欧氏距离有显著优势。
但要注意样本量要求和正态性假设。
马氏距离通常比欧氏距离有显著优势。
但要注意样本量要求和正态性假设。
🎯 23.2 关键要点
异常值检测
• D² ~ χ²(d)
• 设置阈值
• 考虑相关性
• 统计理论支撑
• 设置阈值
• 考虑相关性
• 统计理论支撑
分类与聚类
• 最小距离分类
• 与贝叶斯联系
• GMM聚类
• 椭圆形簇
• 与贝叶斯联系
• GMM聚类
• 椭圆形簇
其他应用
• 特征选择
• 图像匹配
• 金融风险
• 生物信息
• 图像匹配
• 金融风险
• 生物信息
💡 核心洞察
• 应用广泛:从异常检测到分类聚类,马氏距离无处不在
• 理论基础:卡方分布为异常检测提供统计依据
• 实践价值:Python实现简单,scipy提供现成工具
• 注意事项:样本量、正态性、数值稳定性都很重要
• 权衡考虑:马氏距离强大但有前提条件
• 理论基础:卡方分布为异常检测提供统计依据
• 实践价值:Python实现简单,scipy提供现成工具
• 注意事项:样本量、正态性、数值稳定性都很重要
• 权衡考虑:马氏距离强大但有前提条件
✦
23.3
马氏距离的计算与优化
Computation and Optimization
在实际应用中,马氏距离的计算效率和数值稳定性至关重要。 本节将探讨高维数据、大规模数据、稳健估计等实践中的关键问题。
🚨 挑战1:高维数据问题
当数据维度d接近或超过样本量n时,协方差矩阵的估计变得不稳定甚至奇异。
维数灾难
问题根源:
估计d×d协方差矩阵需要d(d+1)/2个参数,
但只有n个样本
估计d×d协方差矩阵需要d(d+1)/2个参数,
但只有n个样本
如果 n < d:Σ̂ 必然奇异(不可逆)
如果 n ≈ d:Σ̂ 数值不稳定
如果 n ≈ d:Σ̂ 数值不稳定
症状表现
1. 矩阵奇异:
det(Σ̂) ≈ 0,无法计算Σ̂⁻¹
det(Σ̂) ≈ 0,无法计算Σ̂⁻¹
2. 条件数大:
最大特征值/最小特征值 → ∞
数值计算极不稳定
最大特征值/最小特征值 → ∞
数值计算极不稳定
3. 过拟合:
Σ̂对训练数据过度拟合,
泛化性能差
Σ̂对训练数据过度拟合,
泛化性能差
解决方案
方案1:正则化
Σ̃ = Σ̂ + λI(岭正则化)
• λ确保矩阵正定
• 改善条件数
• 交叉验证选择λ
Σ̃ = Σ̂ + λI(岭正则化)
• λ确保矩阵正定
• 改善条件数
• 交叉验证选择λ
方案2:收缩估计(Shrinkage)
Σ̃ = (1-α)Σ̂ + αT
• T是目标矩阵(如对角矩阵)
• α∈[0,1]是收缩系数
• Ledoit-Wolf方法自动选择α
Σ̃ = (1-α)Σ̂ + αT
• T是目标矩阵(如对角矩阵)
• α∈[0,1]是收缩系数
• Ledoit-Wolf方法自动选择α
方案3:降维
先用PCA降到d'维(d' << n)
然后在低维空间计算马氏距离
先用PCA降到d'维(d' << n)
然后在低维空间计算马氏距离
方案4:稀疏估计
假设Σ⁻¹是稀疏的(Graphical Lasso)
减少需要估计的参数数量
假设Σ⁻¹是稀疏的(Graphical Lasso)
减少需要估计的参数数量
💡 实践经验
经验法则:
• n > 5d:可以直接使用样本协方差
• 2d < n < 5d:建议使用收缩估计
• n < 2d:必须降维或正则化
• n < d:样本协方差完全不可用
• n > 5d:可以直接使用样本协方差
• 2d < n < 5d:建议使用收缩估计
• n < 2d:必须降维或正则化
• n < d:样本协方差完全不可用
⚡ 挑战2:数值稳定性
即使n > d,直接求逆Σ̂也可能导致数值问题。
问题根源
1. 浮点数精度:
64位浮点数约16位有效数字
条件数大时,误差放大
64位浮点数约16位有效数字
条件数大时,误差放大
2. 矩阵求逆误差:
inv(Σ̂)的误差 ∝ cond(Σ̂) × 机器精度
条件数越大,误差越大
inv(Σ̂)的误差 ∝ cond(Σ̂) × 机器精度
条件数越大,误差越大
3. 累积误差:
(x-μ)ᵀΣ⁻¹(x-μ)涉及多次矩阵运算
误差层层累积
(x-μ)ᵀΣ⁻¹(x-μ)涉及多次矩阵运算
误差层层累积
更好的计算方法
方法1:Cholesky分解
Σ = LLᵀ(L是下三角矩阵)
D² = ||L⁻¹(x-μ)||²
• 只需解三角线性方程组
• 比直接求逆稳定
• 计算复杂度O(d³/6)
Σ = LLᵀ(L是下三角矩阵)
D² = ||L⁻¹(x-μ)||²
• 只需解三角线性方程组
• 比直接求逆稳定
• 计算复杂度O(d³/6)
方法2:SVD分解
Σ = UΛUᵀ(特征值分解)
D² = (x-μ)ᵀUΛ⁻¹Uᵀ(x-μ)
• 最稳定的方法
• 自动处理小特征值
• 计算复杂度较高O(d³)
Σ = UΛUᵀ(特征值分解)
D² = (x-μ)ᵀUΛ⁻¹Uᵀ(x-μ)
• 最稳定的方法
• 自动处理小特征值
• 计算复杂度较高O(d³)
方法3:QR分解
适用于增量更新场景
在线算法的基础
适用于增量更新场景
在线算法的基础
Python实现对比
import numpy as np # ❌ 不推荐:直接求逆 inv_cov = np.linalg.inv(cov) dist_sq = np.dot(diff, np.dot(inv_cov, diff)) # ✅ 推荐:Cholesky分解 L = np.linalg.cholesky(cov) y = np.linalg.solve(L, diff) # 解 Ly = diff dist_sq = np.dot(y, y) # ✅ 最稳定:SVD U, s, _ = np.linalg.svd(cov) inv_s = 1.0 / s inv_s[s < 1e-10] = 0 # 处理小特征值 temp = np.dot(U, inv_s[:, None] * U.T) dist_sq = np.dot(diff, np.dot(temp, diff))
🎯 选择建议
• 正定且条件数小:Cholesky(最快)
• 可能近奇异:SVD(最稳定)
• 高维数据:先降维再计算
• 大规模数据:考虑近似方法
• 可能近奇异:SVD(最稳定)
• 高维数据:先降维再计算
• 大规模数据:考虑近似方法
🛡️ 挑战3:稳健估计
样本均值和协方差对异常值极其敏感,一个异常值就能严重扭曲估计。
异常值的影响
悖论:
我们用马氏距离检测异常值,
但异常值会污染μ̂和Σ̂,
导致无法正确识别异常值!
我们用马氏距离检测异常值,
但异常值会污染μ̂和Σ̂,
导致无法正确识别异常值!
掩蔽效应(Masking):
异常值拉动均值和协方差,
使自己看起来"正常"
异常值拉动均值和协方差,
使自己看起来"正常"
稳健估计方法
1. 最小协方差行列式(MCD)
• 寻找h个点(h≈n/2)使det(Σ)最小
• 用这h个点估计μ和Σ
• 最多可容忍50%的异常值
• 计算复杂,但非常稳健
• 寻找h个点(h≈n/2)使det(Σ)最小
• 用这h个点估计μ和Σ
• 最多可容忍50%的异常值
• 计算复杂,但非常稳健
2. M估计量
• 加权最小二乘,异常点权重小
• 迭代重加权算法
• Huber估计、Tukey估计等
• 加权最小二乘,异常点权重小
• 迭代重加权算法
• Huber估计、Tukey估计等
3. 截尾估计
• 移除最极端的α%数据
• 用剩余数据估计
• 简单但效果有限
• 移除最极端的α%数据
• 用剩余数据估计
• 简单但效果有限
Python实现:MCD
from sklearn.covariance import MinCovDet # 稳健协方差估计 mcd = MinCovDet(support_fraction=0.5, random_state=0) mcd.fit(X) # 稳健的均值和协方差 robust_mean = mcd.location_ robust_cov = mcd.covariance_ # 计算稳健马氏距离 robust_dist = mcd.mahalanobis(X) # 异常值检测 threshold = chi2.ppf(0.95, df=X.shape[1]) outliers = robust_dist > threshold
⚖️ 权衡考虑
稳健估计的代价:
• 计算成本高(MCD约O(n²d³))
• 在无异常值时效率略低于经典估计
• 需要足够样本量(n > 5d)
建议:怀疑有异常值时使用稳健估计
• 计算成本高(MCD约O(n²d³))
• 在无异常值时效率略低于经典估计
• 需要足够样本量(n > 5d)
建议:怀疑有异常值时使用稳健估计
📈 挑战4:大规模数据
当数据量n很大时,完整存储和计算Σ变得内存和时间上不可行。
挑战
内存:d×d矩阵需要8d²字节(d=1000→8MB)
时间:计算Σ需要O(nd²),求逆O(d³)
更新:新增数据时需要重新计算整个Σ
解决方案
1. 在线/增量算法
• Welford算法更新均值和方差
• 无需存储所有数据
• O(d²)内存,O(d²)时间每个样本
• Welford算法更新均值和方差
• 无需存储所有数据
• O(d²)内存,O(d²)时间每个样本
2. 分块处理
• 将数据分成小批次
• 每批计算局部统计量
• 合并得到全局统计量
• 将数据分成小批次
• 每批计算局部统计量
• 合并得到全局统计量
3. 随机采样
• 用子样本估计Σ
• 理论保证:样本量约O(d log d)足够
• 适用于非常大的n
• 用子样本估计Σ
• 理论保证:样本量约O(d log d)足够
• 适用于非常大的n
4. 低秩近似
• Σ ≈ UU^T + σ²I(低秩+对角)
• Woodbury矩阵恒等式快速求逆
• 适用于数据在低维子空间
• Σ ≈ UU^T + σ²I(低秩+对角)
• Woodbury矩阵恒等式快速求逆
• 适用于数据在低维子空间
在线算法示例
class OnlineMahalanobis:
def __init__(self, d):
self.n = 0
self.mean = np.zeros(d)
self.M2 = np.zeros((d, d)) # 二阶矩
def update(self, x):
"""增量更新统计量"""
self.n += 1
delta = x - self.mean
self.mean += delta / self.n
delta2 = x - self.mean
self.M2 += np.outer(delta, delta2)
def get_cov(self):
"""获取当前协方差估计"""
if self.n < 2:
return None
return self.M2 / (self.n - 1)
def mahalanobis(self, x):
"""计算马氏距离"""
cov = self.get_cov()
if cov is None:
return None
diff = x - self.mean
# 使用Cholesky求解
L = np.linalg.cholesky(cov + 1e-6*np.eye(len(x)))
y = np.linalg.solve(L, diff)
return np.sqrt(np.dot(y, y))🚀 性能对比
• 批处理:O(nd²)时间,O(nd)内存
• 在线算法:O(d²)时间每样本,O(d²)内存
• 低秩近似:O(dk²)时间,O(dk)内存(k<<d)
• 采样:O(md²)时间(m是样本量,m<<n)
• 在线算法:O(d²)时间每样本,O(d²)内存
• 低秩近似:O(dk²)时间,O(dk)内存(k<<d)
• 采样:O(md²)时间(m是样本量,m<<n)
⏱️ 计算复杂度总结
| 操作 | 时间复杂度 | 空间复杂度 | 备注 |
|---|---|---|---|
| 计算Σ | O(nd²) | O(nd) | n个样本,d维 |
| 直接求逆 | O(d³) | O(d²) | 不推荐 |
| Cholesky | O(d³/6) | O(d²) | 最快的稳定方法 |
| SVD | O(d³) | O(d²) | 最稳定 |
| 计算单个D² | O(d²) | O(d) | 已有Σ⁻¹ |
| 计算n个D² | O(nd²) | O(n) | 批量计算 |
| MCD稳健估计 | O(n²d³) | O(nd) | 计算昂贵 |
小数据
n < 10,000
d < 100
→ 直接计算
d < 100
→ 直接计算
中等数据
n ~ 100,000
d ~ 1,000
→ 分块/采样
d ~ 1,000
→ 分块/采样
大数据
n > 1,000,000
→ 在线算法
d > 10,000
→ 降维/低秩
→ 在线算法
d > 10,000
→ 降维/低秩
✨ 最佳实践指南
1️⃣
数据预处理
• 检查缺失值和异常值
• 考虑数据变换(如log变换)
• 标准化可选(马氏距离自动标准化)
• 考虑数据变换(如log变换)
• 标准化可选(马氏距离自动标准化)
2️⃣
样本量检查
• 计算n/d比率
• n < 2d:必须正则化或降维
• 2d ≤ n < 5d:使用收缩估计
• n ≥ 5d:可以使用经典估计
• n < 2d:必须正则化或降维
• 2d ≤ n < 5d:使用收缩估计
• n ≥ 5d:可以使用经典估计
3️⃣
选择合适的方法
有异常值?→ 稳健估计(MCD)
高维?→ 收缩/正则化
大数据?→ 在线算法
实时?→ 预计算Σ⁻¹
高维?→ 收缩/正则化
大数据?→ 在线算法
实时?→ 预计算Σ⁻¹
4️⃣
数值稳定性
• 使用Cholesky或SVD,避免直接求逆
• 添加小量正则化(cov + 1e-6*I)
• 检查条件数(cond(Σ) < 1e10)
• 添加小量正则化(cov + 1e-6*I)
• 检查条件数(cond(Σ) < 1e10)
5️⃣
验证结果
• 检查D²的分布(应该近似χ²(d))
• QQ图验证正态性
• 交叉验证评估性能
• 可视化等距离椭圆
• QQ图验证正态性
• 交叉验证评估性能
• 可视化等距离椭圆
6️⃣
性能优化
• 预计算并缓存Σ⁻¹
• 批量计算多个距离
• 考虑GPU加速(大规模)
• 使用专业库(sklearn, scipy)
• 批量计算多个距离
• 考虑GPU加速(大规模)
• 使用专业库(sklearn, scipy)
🔄 完整工作流程
完整示例:异常值检测
import numpy as np
from sklearn.covariance import EmpiricalCovariance, MinCovDet
from sklearn.covariance import LedoitWolf
from scipy.stats import chi2
import matplotlib.pyplot as plt
def robust_mahalanobis_outliers(X, alpha=0.05, method='mcd'):
"""
完整的异常值检测流程
Parameters:
-----------
X : array-like (n, d)
数据矩阵
alpha : float
显著性水平
method : str
'empirical', 'mcd', 'ledoit_wolf'
"""
n, d = X.shape
# 1. 检查样本量
if n < 2 * d:
print(f"警告:n={n}, d={d}, n/d={n/d:.2f} < 2")
print("建议:使用收缩估计或降维")
method = 'ledoit_wolf'
# 2. 选择估计器
if method == 'empirical':
estimator = EmpiricalCovariance()
elif method == 'mcd':
estimator = MinCovDet(support_fraction=0.5)
elif method == 'ledoit_wolf':
estimator = LedoitWolf()
# 3. 拟合估计器
estimator.fit(X)
# 4. 计算马氏距离
dist_sq = estimator.mahalanobis(X)
# 5. 设置阈值
threshold = chi2.ppf(1 - alpha, df=d)
# 6. 识别异常值
outliers = dist_sq > threshold
# 7. 可视化(2D情况)
if d == 2:
plt.figure(figsize=(10, 5))
# 左图:数据点
plt.subplot(1, 2, 1)
plt.scatter(X[~outliers, 0], X[~outliers, 1],
c='blue', label='Normal', alpha=0.6)
plt.scatter(X[outliers, 0], X[outliers, 1],
c='red', label='Outlier', alpha=0.8)
plt.title('Outlier Detection')
plt.legend()
# 右图:距离分布
plt.subplot(1, 2, 2)
plt.hist(dist_sq[~outliers], bins=30,
alpha=0.6, label='Normal', density=True)
plt.hist(dist_sq[outliers], bins=10,
alpha=0.6, label='Outlier', density=True)
plt.axvline(threshold, color='red',
linestyle='--', label='Threshold')
plt.xlabel('Mahalanobis Distance²')
plt.legend()
plt.tight_layout()
plt.show()
# 8. 返回结果
return {
'outliers': outliers,
'distances': np.sqrt(dist_sq),
'threshold': np.sqrt(threshold),
'mean': estimator.location_,
'cov': estimator.covariance_,
'n_outliers': outliers.sum()
}
# 使用示例
# result = robust_mahalanobis_outliers(X, alpha=0.01, method='mcd')
# print(f"检测到 {result['n_outliers']} 个异常值")💡 代码亮点
• 自动方法选择:根据n/d比率选择合适方法
• 多种估计器:经典、稳健、收缩三种选择
• 完整诊断:返回所有关键信息
• 可视化:二维情况自动绘图
• 统计理论:基于卡方分布设置阈值
• 多种估计器:经典、稳健、收缩三种选择
• 完整诊断:返回所有关键信息
• 可视化:二维情况自动绘图
• 统计理论:基于卡方分布设置阈值
🎯 23.3 关键要点
高维问题
• n < d不可用
• 正则化/收缩
• 降维方法
• 稀疏估计
• 正则化/收缩
• 降维方法
• 稀疏估计
数值稳定
• Cholesky分解
• SVD最稳定
• 避免直接求逆
• 处理小特征值
• SVD最稳定
• 避免直接求逆
• 处理小特征值
稳健估计
• MCD方法
• M估计量
• 对抗异常值
• 掩蔽效应
• M估计量
• 对抗异常值
• 掩蔽效应
大规模数据
• 在线算法
• 分块处理
• 随机采样
• 低秩近似
• 分块处理
• 随机采样
• 低秩近似
最佳实践
• 检查n/d比率
• 选择合适方法
• 验证结果
• 性能优化
• 选择合适方法
• 验证结果
• 性能优化
💡 核心洞察
• 实践挑战:高维、数值稳定、异常值、大规模是四大挑战
• 解决方案:正则化、Cholesky、稳健估计、在线算法
• 权衡考虑:准确性vs效率、稳健性vs速度
• 工具完备:sklearn提供了完整的工具链
• 实战导向:完整代码示例可直接使用
• 解决方案:正则化、Cholesky、稳健估计、在线算法
• 权衡考虑:准确性vs效率、稳健性vs速度
• 工具完备:sklearn提供了完整的工具链
• 实战导向:完整代码示例可直接使用
✦
23.4
综合案例与总结
Case Study and Summary
本节通过完整的综合案例, 展示马氏距离在实际数据分析中的应用, 并对本章内容进行系统总结。
📊 综合案例:信用卡欺诈检测
让我们通过一个完整的信用卡欺诈检测案例,展示马氏距离的实际应用。
问题背景
任务:检测信用卡交易中的异常行为
数据:30个特征(交易金额、时间、地点等)
挑战:
• 特征量纲差异大(金额vs时间)
• 特征间高度相关
• 正常交易远多于欺诈(不平衡)
• 实时检测要求
• 特征量纲差异大(金额vs时间)
• 特征间高度相关
• 正常交易远多于欺诈(不平衡)
• 实时检测要求
完整解决方案
import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.covariance import EmpiricalCovariance
from scipy.stats import chi2
import matplotlib.pyplot as plt
# 步骤1:数据加载与预处理
def preprocess_data(df):
"""预处理信用卡交易数据"""
# 移除缺失值
df = df.dropna()
# 分离正常交易(用于训练)
normal_transactions = df[df['fraud'] == 0].copy()
X_normal = normal_transactions.drop(['fraud'], axis=1)
# 特征选择:移除高度相关的特征
corr_matrix = X_normal.corr().abs()
upper = corr_matrix.where(
np.triu(np.ones(corr_matrix.shape), k=1).astype(bool)
)
to_drop = [col for col in upper.columns
if any(upper[col] > 0.95)]
X_normal = X_normal.drop(to_drop, axis=1)
return X_normal, df
# 步骤2:构建马氏距离模型
class FraudDetector:
def __init__(self, contamination=0.01, use_pca=True):
self.contamination = contamination
self.use_pca = use_pca
self.pca = None
self.cov_estimator = None
self.threshold = None
def fit(self, X_normal):
"""在正常交易上训练模型"""
n, d = X_normal.shape
# 降维(如果维度过高)
if self.use_pca and d > 20:
# 保留95%方差
self.pca = PCA(n_components=0.95)
X_train = self.pca.fit_transform(X_normal)
print(f"PCA降维:{d} → {X_train.shape[1]}")
else:
X_train = X_normal
# 估计协方差(根据样本量选择方法)
n_train, d_train = X_train.shape
if n_train > 5 * d_train:
# 样本充足,使用经典估计
self.cov_estimator = EmpiricalCovariance()
print("使用经典协方差估计")
else:
# 样本不足,使用收缩估计
from sklearn.covariance import LedoitWolf
self.cov_estimator = LedoitWolf()
print("使用Ledoit-Wolf收缩估计")
self.cov_estimator.fit(X_train)
# 计算训练数据的马氏距离
dist_sq = self.cov_estimator.mahalanobis(X_train)
# 设置阈值(卡方分布)
self.threshold = chi2.ppf(
1 - self.contamination,
df=d_train
)
print(f"阈值设置为:{np.sqrt(self.threshold):.2f}")
print(f"训练集异常率:{(dist_sq > self.threshold).mean():.2%}")
return self
def predict(self, X):
"""预测新交易是否为欺诈"""
# 应用相同的预处理
if self.pca is not None:
X = self.pca.transform(X)
# 计算马氏距离
dist_sq = self.cov_estimator.mahalanobis(X)
# 判断异常
is_fraud = dist_sq > self.threshold
return is_fraud, np.sqrt(dist_sq)
def score(self, X):
"""返回异常分数(距离)"""
if self.pca is not None:
X = self.pca.transform(X)
dist_sq = self.cov_estimator.mahalanobis(X)
return np.sqrt(dist_sq)
# 步骤3:模型评估
def evaluate_model(detector, X_test, y_test):
"""评估模型性能"""
predictions, distances = detector.predict(X_test)
from sklearn.metrics import (
classification_report,
confusion_matrix,
roc_auc_score,
roc_curve
)
# 混淆矩阵
cm = confusion_matrix(y_test, predictions)
print("\n混淆矩阵:")
print(cm)
# 分类报告
print("\n分类报告:")
print(classification_report(y_test, predictions))
# ROC-AUC
auc = roc_auc_score(y_test, distances)
print(f"\nROC-AUC: {auc:.4f}")
# 可视化
plt.figure(figsize=(12, 4))
# 距离分布
plt.subplot(1, 3, 1)
plt.hist(distances[y_test==0], bins=50,
alpha=0.6, label='Normal', density=True)
plt.hist(distances[y_test==1], bins=30,
alpha=0.6, label='Fraud', density=True)
plt.axvline(np.sqrt(detector.threshold),
color='red', linestyle='--', label='Threshold')
plt.xlabel('Mahalanobis Distance')
plt.legend()
plt.title('Distance Distribution')
# ROC曲线
plt.subplot(1, 3, 2)
fpr, tpr, _ = roc_curve(y_test, distances)
plt.plot(fpr, tpr, label=f'AUC={auc:.3f}')
plt.plot([0, 1], [0, 1], 'k--')
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.legend()
plt.title('ROC Curve')
# 混淆矩阵热图
plt.subplot(1, 3, 3)
plt.imshow(cm, cmap='Blues')
plt.colorbar()
plt.title('Confusion Matrix')
plt.tight_layout()
plt.show()
# 步骤4:使用流程
# df = pd.read_csv('credit_card_transactions.csv')
# X_normal, df = preprocess_data(df)
#
# detector = FraudDetector(contamination=0.01, use_pca=True)
# detector.fit(X_normal)
#
# X_test = df[df['is_test']].drop(['fraud', 'is_test'], axis=1)
# y_test = df[df['is_test']]['fraud']
# evaluate_model(detector, X_test, y_test)✅ 关键决策
• PCA降维:d> 20时使用
• 协方差估计:根据n/d自动选择
• 阈值设置:卡方分布理论指导
• 性能评估:ROC-AUC而非准确率
• 协方差估计:根据n/d自动选择
• 阈值设置:卡方分布理论指导
• 性能评估:ROC-AUC而非准确率
📈 预期结果
• 检测率:80%+ 欺诈被发现
• 误报率:<1% 正常交易误判
• AUC:0.90+ 综合性能
• 推理时间:<10ms 满足实时需求
• 误报率:<1% 正常交易误判
• AUC:0.90+ 综合性能
• 推理时间:<10ms 满足实时需求
💡 为什么马氏距离有效?
• 自动标准化:处理不同量纲的特征
• 考虑相关性:捕捉特征间的关联模式
• 理论基础:卡方分布提供统计阈值
• 无监督:只需正常交易训练,适合不平衡数据
• 考虑相关性:捕捉特征间的关联模式
• 理论基础:卡方分布提供统计阈值
• 无监督:只需正常交易训练,适合不平衡数据
⚖️ 欧氏距离 vs 马氏距离:全面对比
| 维度 | 欧氏距离 | 马氏距离 | 获胜者 |
|---|---|---|---|
| 定义 | √[Σ(xᵢ-yᵢ)²] | √[(x-y)ᵀΣ⁻¹(x-y)] | - |
| 量纲敏感性 | ❌ 高度敏感 | ✅ 自动标准化 | 🏆 马氏 |
| 处理相关性 | ❌ 忽略 | ✅ 考虑 | 🏆 马氏 |
| 方差差异 | ❌ 一视同仁 | ✅ 自适应 | 🏆 马氏 |
| 计算复杂度 | ✅ O(d) 极快 | ❌ O(d²) 较慢 | 🏆 欧氏 |
| 样本量要求 | ✅ 无要求 | ⚠️ n > d | 🏆 欧氏 |
| 实现难度 | ✅ 极简单 | ⚠️ 中等 | 🏆 欧氏 |
| 数值稳定性 | ✅ 稳定 | ⚠️ 需要注意 | 🏆 欧氏 |
| 异常值检测 | ❌ 效果差 | ✅ 优秀 | 🏆 马氏 |
| 理论基础 | ⚠️ 简单 | ✅ 统计理论 | 🏆 马氏 |
🏆 马氏距离优势(5票)
• 量纲自动处理
• 考虑特征相关性
• 适应方差差异
• 异常检测优秀
• 坚实理论基础
• 考虑特征相关性
• 适应方差差异
• 异常检测优秀
• 坚实理论基础
🏆 欧氏距离优势(4票)
• 计算极快
• 无样本量要求
• 实现极简单
• 数值稳定
• 无样本量要求
• 实现极简单
• 数值稳定
🎯 选择建议
优先马氏距离:
• 特征有不同量纲或方差
• 特征间存在相关性
• 异常值检测任务
• 有足够样本量(n > 5d)
优先欧氏距离:
• 特征已标准化且独立
• 计算资源极受限
• 样本量很小(n ≈ d)
• 简单快速原型
• 特征有不同量纲或方差
• 特征间存在相关性
• 异常值检测任务
• 有足够样本量(n > 5d)
优先欧氏距离:
• 特征已标准化且独立
• 计算资源极受限
• 样本量很小(n ≈ d)
• 简单快速原型
🌳 方法选择决策树
根据数据特征和任务需求,选择合适的距离度量方法。
❓ 特征是否有不同量纲?
是 → 继续下一步
否(已标准化) → 考虑欧氏距离
否(已标准化) → 考虑欧氏距离
❓ 特征间是否相关?
是(相关性> 0.3) → 继续下一步
否(近独立) → 标准化后用欧氏距离
否(近独立) → 标准化后用欧氏距离
❓ 样本量 n 与维度 d 的关系?
n > 5d:✅ 直接用马氏距离(经典估计)
2d < n < 5d:⚠️ 用马氏距离+收缩估计
d < n < 2d:⚠️ PCA降维后用马氏距离
n ≤ d:❌ 必须降维或用欧氏距离
❓ 数据中有异常值?
是或怀疑有 → 使用稳健马氏距离(MCD)
否 → 使用标准马氏距离
否 → 使用标准马氏距离
❓ 实时性要求?
严格实时 → 预计算Σ⁻¹,使用Cholesky
批处理 → 标准实现即可
批处理 → 标准实现即可
🎯 快速决策表
简单数据:欧氏距离
复杂数据:马氏距离
高维数据:PCA+马氏
有异常值:稳健马氏(MCD)
大规模数据:在线马氏
实时系统:预计算+Cholesky
📚 本章总结
23.1 基本概念
• 欧氏距离的局限性
• 马氏距离定义:D²=(x-μ)ᵀΣ⁻¹(x-μ)
• 几何意义:椭圆→圆变换
• 5个重要性质
• 标准化的本质
• 马氏距离定义:D²=(x-μ)ᵀΣ⁻¹(x-μ)
• 几何意义:椭圆→圆变换
• 5个重要性质
• 标准化的本质
23.3 计算优化
• 高维问题:正则化/收缩
• 数值稳定:Cholesky/SVD
• 稳健估计:MCD方法
• 大规模:在线算法
• 复杂度分析与最佳实践
• 数值稳定:Cholesky/SVD
• 稳健估计:MCD方法
• 大规模:在线算法
• 复杂度分析与最佳实践
23.2 实际应用
• 异常值检测(卡方分布)
• 分类算法(最小距离)
• 聚类分析(GMM)
• 特征选择与降维
• 6个应用领域
• 分类算法(最小距离)
• 聚类分析(GMM)
• 特征选择与降维
• 6个应用领域
23.4 综合实践
• 完整案例:欺诈检测
• 欧氏vs马氏全面对比
• 方法选择决策树
• 实战代码与技巧
• 性能评估方法
• 欧氏vs马氏全面对比
• 方法选择决策树
• 实战代码与技巧
• 性能评估方法
🎯 核心要点
1. 核心价值:马氏距离自动适应数据分布,解决欧氏距离的三大问题
2. 理论基础:协方差矩阵Σ⁻¹包含了所有分布信息
3. 实践关键:样本量、数值稳定性、异常值是三大挑战
4. 应用广泛:从异常检测到分类聚类,理论与实践结合
5. 工具完备:sklearn提供完整工具链,代码实现简单
2. 理论基础:协方差矩阵Σ⁻¹包含了所有分布信息
3. 实践关键:样本量、数值稳定性、异常值是三大挑战
4. 应用广泛:从异常检测到分类聚类,理论与实践结合
5. 工具完备:sklearn提供完整工具链,代码实现简单
📖 进一步学习
📚
相关主题
• 多元正态分布:马氏距离的概率基础
• 协方差矩阵:深入理解Σ的性质
• 主成分分析(PCA):降维与马氏距离
• 高斯混合模型(GMM):聚类应用
• 稳健统计:处理异常值的理论
• 协方差矩阵:深入理解Σ的性质
• 主成分分析(PCA):降维与马氏距离
• 高斯混合模型(GMM):聚类应用
• 稳健统计:处理异常值的理论
🔧
高级技术
• 核马氏距离:非线性推广
• 局部马氏距离:自适应度量学习
• Graphical Lasso:稀疏协方差估计
• 流形学习:非欧空间的距离
• 深度度量学习:神经网络学习距离
• 局部马氏距离:自适应度量学习
• Graphical Lasso:稀疏协方差估计
• 流形学习:非欧空间的距离
• 深度度量学习:神经网络学习距离
💻
实践项目
• 在UCI数据集上实现异常检测
• 对比不同协方差估计方法
• 开发实时欺诈检测系统
• 可视化等马氏距离椭圆
• 基准测试不同距离度量
• 对比不同协方差估计方法
• 开发实时欺诈检测系统
• 可视化等马氏距离椭圆
• 基准测试不同距离度量
🎯 第23章 最终要点
理论基础
• D²=ΔᵀΣ⁻¹Δ
• 椭圆→圆变换
• 卡方分布
• 5个性质
• 椭圆→圆变换
• 卡方分布
• 5个性质
核心应用
• 异常检测
• 分类聚类
• 特征工程
• 6大领域
• 分类聚类
• 特征工程
• 6大领域
实践挑战
• 高维问题
• 数值稳定
• 异常值
• 大规模
• 数值稳定
• 异常值
• 大规模
方法选择
• 决策树
• 对比分析
• 最佳实践
• 工具链
• 对比分析
• 最佳实践
• 工具链
💡 最终洞察
马氏距离的本质:一种智能的、自适应的距离度量,通过协方差矩阵的逆Σ⁻¹, 自动考虑了数据的量纲、方差和相关性。 它把复杂的椭圆形数据分布"拉"成简单的圆形,让距离计算更加合理。 虽然计算成本高于欧氏距离,但在异常检测、模式识别等领域有无可替代的价值。 掌握马氏距离,就掌握了从几何空间到概率空间的桥梁!
✦
23.5
可视化与直观理解
Visualization and Intuition
马氏距离的几何意义最好通过可视化来理解。 本节将展示如何绘制等距离椭圆、可视化数据分布, 以及理解马氏距离与欧氏距离的视觉差异。
📊 二维可视化:等距离椭圆
在二维空间中,马氏距离的等距离曲线是椭圆,而欧氏距离是圆。
核心概念
等距离椭圆:
所有满足 D(x, μ) = c 的点x构成一个椭圆
所有满足 D(x, μ) = c 的点x构成一个椭圆
(x-μ)ᵀΣ⁻¹(x-μ) = c²
椭圆参数:
• 中心:μ(均值向量)
• 形状:由Σ决定
• 方向:Σ的特征向量
• 长短轴:Σ的特征值
• 中心:μ(均值向量)
• 形状:由Σ决定
• 方向:Σ的特征向量
• 长短轴:Σ的特征值
完整绘图代码
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import chi2
from matplotlib.patches import Ellipse
def plot_mahalanobis_ellipses(X, levels=[0.95, 0.99]):
"""
绘制马氏距离等距离椭圆
Parameters:
-----------
X : array-like (n, 2)
二维数据
levels : list
置信水平列表
"""
# 计算均值和协方差
mean = np.mean(X, axis=0)
cov = np.cov(X.T)
# 创建图形
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
# 子图1:原始数据 + 马氏距离椭圆
ax1 = axes[0]
ax1.scatter(X[:, 0], X[:, 1], alpha=0.5, s=20)
ax1.scatter(mean[0], mean[1], c='red', s=100,
marker='x', linewidths=3, label='Mean')
# 绘制马氏距离椭圆
colors = ['blue', 'green', 'orange']
for level, color in zip(levels, colors):
# 卡方分布临界值
chi2_val = chi2.ppf(level, df=2)
# 计算椭圆参数
eigenvalues, eigenvectors = np.linalg.eigh(cov)
angle = np.degrees(np.arctan2(eigenvectors[1, 1],
eigenvectors[0, 1]))
width = 2 * np.sqrt(chi2_val * eigenvalues[0])
height = 2 * np.sqrt(chi2_val * eigenvalues[1])
# 绘制椭圆
ellipse = Ellipse(mean, width, height, angle=angle,
facecolor='none', edgecolor=color,
linewidth=2, label=f'{level*100:.0f}%')
ax1.add_patch(ellipse)
ax1.set_title('Mahalanobis Distance Ellipses', fontsize=12)
ax1.set_xlabel('X1')
ax1.set_ylabel('X2')
ax1.legend()
ax1.grid(True, alpha=0.3)
ax1.axis('equal')
# 子图2:欧氏距离圆
ax2 = axes[1]
ax2.scatter(X[:, 0], X[:, 1], alpha=0.5, s=20)
ax2.scatter(mean[0], mean[1], c='red', s=100,
marker='x', linewidths=3)
# 绘制欧氏距离圆
for level, color in zip(levels, colors):
# 计算半径(使用标准差的平均值)
radius = np.sqrt(chi2.ppf(level, df=2)) * np.mean(np.sqrt(np.diag(cov)))
circle = plt.Circle(mean, radius, facecolor='none',
edgecolor=color, linewidth=2,
label=f'{level*100:.0f}%')
ax2.add_patch(circle)
ax2.set_title('Euclidean Distance Circles', fontsize=12)
ax2.set_xlabel('X1')
ax2.set_ylabel('X2')
ax2.legend()
ax2.grid(True, alpha=0.3)
ax2.axis('equal')
# 子图3:马氏距离热图
ax3 = axes[2]
# 创建网格
x_min, x_max = X[:, 0].min() - 2, X[:, 0].max() + 2
y_min, y_max = X[:, 1].min() - 2, X[:, 1].max() + 2
xx, yy = np.meshgrid(np.linspace(x_min, x_max, 100),
np.linspace(y_min, y_max, 100))
# 计算每个点的马氏距离
grid_points = np.c_[xx.ravel(), yy.ravel()]
diff = grid_points - mean
inv_cov = np.linalg.inv(cov)
dist_sq = np.sum(np.dot(diff, inv_cov) * diff, axis=1)
dist = np.sqrt(dist_sq).reshape(xx.shape)
# 绘制热图
contour = ax3.contourf(xx, yy, dist, levels=20, cmap='viridis')
ax3.scatter(X[:, 0], X[:, 1], c='red', s=20, alpha=0.6)
ax3.scatter(mean[0], mean[1], c='white', s=100,
marker='x', linewidths=3)
# 添加等距离线
contour_lines = ax3.contour(xx, yy, dist,
levels=[np.sqrt(chi2.ppf(0.95, df=2)),
np.sqrt(chi2.ppf(0.99, df=2))],
colors=['white', 'yellow'],
linewidths=2, linestyles='--')
ax3.clabel(contour_lines, inline=True, fontsize=8)
plt.colorbar(contour, ax=ax3, label='Mahalanobis Distance')
ax3.set_title('Mahalanobis Distance Heatmap', fontsize=12)
ax3.set_xlabel('X1')
ax3.set_ylabel('X2')
plt.tight_layout()
plt.show()
# 示例使用
# 生成相关数据
np.random.seed(42)
mean = [0, 0]
cov = [[2, 1.5], [1.5, 1]] # 相关性 = 1.5/√(2*1) ≈ 0.75
X = np.random.multivariate_normal(mean, cov, 200)
# 绘制
plot_mahalanobis_ellipses(X, levels=[0.68, 0.95, 0.997])左图:马氏椭圆
• 椭圆形状由Σ决定
• 方向沿特征向量
• 长短轴对应特征值
• 自动适应相关性
• 方向沿特征向量
• 长短轴对应特征值
• 自动适应相关性
中图:欧氏圆
• 完美圆形
• 各方向平等
• 不考虑相关性
• 可能覆盖不当
• 各方向平等
• 不考虑相关性
• 可能覆盖不当
右图:距离热图
• 颜色表示距离
• 等距离线
• 直观展示分布
• 异常值明显
• 等距离线
• 直观展示分布
• 异常值明显
🎮 交互式演示:调整协方差
通过调整协方差矩阵的参数,观察马氏距离椭圆的变化。
交互式代码
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
from matplotlib.patches import Ellipse
def interactive_mahalanobis():
"""交互式马氏距离椭圆演示"""
# 初始参数
init_var1 = 2.0
init_var2 = 1.0
init_corr = 0.5
# 创建图形
fig, ax = plt.subplots(figsize=(10, 8))
plt.subplots_adjust(left=0.1, bottom=0.25)
# 生成数据
np.random.seed(42)
n_points = 200
def update_plot(var1, var2, corr):
ax.clear()
# 构建协方差矩阵
cov = [[var1, corr * np.sqrt(var1 * var2)],
[corr * np.sqrt(var1 * var2), var2]]
# 生成数据
mean = [0, 0]
X = np.random.multivariate_normal(mean, cov, n_points)
# 绘制数据点
ax.scatter(X[:, 0], X[:, 1], alpha=0.5, s=20, c='blue')
ax.scatter(0, 0, c='red', s=100, marker='x',
linewidths=3, label='Center', zorder=10)
# 绘制马氏距离椭圆
eigenvalues, eigenvectors = np.linalg.eigh(cov)
angle = np.degrees(np.arctan2(eigenvectors[1, 1],
eigenvectors[0, 1]))
colors = ['green', 'orange', 'red']
levels = [1, 2, 3] # 标准差倍数
for level, color in zip(levels, colors):
width = 2 * np.sqrt(level**2 * eigenvalues[0])
height = 2 * np.sqrt(level**2 * eigenvalues[1])
ellipse = Ellipse([0, 0], width, height, angle=angle,
facecolor='none', edgecolor=color,
linewidth=2, label=f'{level}σ',
linestyle='--' if level > 1 else '-')
ax.add_patch(ellipse)
# 绘制主轴方向
for i in range(2):
length = 2 * np.sqrt(eigenvalues[i])
dx = length * eigenvectors[0, i]
dy = length * eigenvectors[1, i]
ax.arrow(0, 0, dx, dy, head_width=0.2,
head_length=0.3, fc='black', ec='black',
alpha=0.5, linestyle='--')
# 设置
ax.set_xlim(-8, 8)
ax.set_ylim(-8, 8)
ax.set_xlabel('X1', fontsize=12)
ax.set_ylabel('X2', fontsize=12)
ax.set_title(f'Variance: ({var1:.1f}, {var2:.1f}), '
f'Correlation: {corr:.2f}', fontsize=14)
ax.legend()
ax.grid(True, alpha=0.3)
ax.axis('equal')
# 显示协方差矩阵
text = f'Σ = [[{var1:.2f}, {corr * np.sqrt(var1 * var2):.2f}]\n'
text += f' [{corr * np.sqrt(var1 * var2):.2f}, {var2:.2f}]]'
ax.text(0.02, 0.98, text, transform=ax.transAxes,
fontsize=10, verticalalignment='top',
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8))
# 初始绘制
update_plot(init_var1, init_var2, init_corr)
# 创建滑块
ax_var1 = plt.axes([0.1, 0.15, 0.8, 0.03])
ax_var2 = plt.axes([0.1, 0.10, 0.8, 0.03])
ax_corr = plt.axes([0.1, 0.05, 0.8, 0.03])
slider_var1 = Slider(ax_var1, 'Var(X1)', 0.1, 5.0,
valinit=init_var1, valstep=0.1)
slider_var2 = Slider(ax_var2, 'Var(X2)', 0.1, 5.0,
valinit=init_var2, valstep=0.1)
slider_corr = Slider(ax_corr, 'Correlation', -0.95, 0.95,
valinit=init_corr, valstep=0.05)
# 更新函数
def update(val):
var1 = slider_var1.val
var2 = slider_var2.val
corr = slider_corr.val
update_plot(var1, var2, corr)
fig.canvas.draw_idle()
slider_var1.on_changed(update)
slider_var2.on_changed(update)
slider_corr.on_changed(update)
plt.show()
# 运行交互式演示
# interactive_mahalanobis()🎛️ 可调参数
• Var(X1):第一维方差
• Var(X2):第二维方差
• Correlation:相关系数ρ
• 实时更新椭圆形状
• Var(X2):第二维方差
• Correlation:相关系数ρ
• 实时更新椭圆形状
👀 观察要点
• 方差↑ → 椭圆该方向拉长
• 相关性↑ → 椭圆倾斜度↑
• ρ=0 → 椭圆轴对齐坐标轴
• ρ=±1 → 椭圆退化为直线
• 相关性↑ → 椭圆倾斜度↑
• ρ=0 → 椭圆轴对齐坐标轴
• ρ=±1 → 椭圆退化为直线
🌐 三维可视化:等距离椭球
在三维空间中,马氏距离的等距离曲面是椭球。
3D绘图代码
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
def plot_3d_mahalanobis(mean, cov, n_points=1000):
"""
绘制三维马氏距离椭球
Parameters:
-----------
mean : array-like (3,)
均值向量
cov : array-like (3, 3)
协方差矩阵
n_points : int
采样点数量
"""
# 生成数据
X = np.random.multivariate_normal(mean, cov, n_points)
# 创建图形
fig = plt.figure(figsize=(15, 5))
# 子图1:3D散点图
ax1 = fig.add_subplot(131, projection='3d')
ax1.scatter(X[:, 0], X[:, 1], X[:, 2],
c='blue', alpha=0.3, s=10)
ax1.scatter(mean[0], mean[1], mean[2],
c='red', s=100, marker='x')
ax1.set_xlabel('X1')
ax1.set_ylabel('X2')
ax1.set_zlabel('X3')
ax1.set_title('3D Data Distribution')
# 子图2:等距离椭球
ax2 = fig.add_subplot(132, projection='3d')
# 计算椭球参数
eigenvalues, eigenvectors = np.linalg.eigh(cov)
# 生成球面
u = np.linspace(0, 2 * np.pi, 50)
v = np.linspace(0, np.pi, 50)
x_sphere = np.outer(np.cos(u), np.sin(v))
y_sphere = np.outer(np.sin(u), np.sin(v))
z_sphere = np.outer(np.ones_like(u), np.cos(v))
# 转换为椭球(1σ)
sphere_points = np.stack([x_sphere.flatten(),
y_sphere.flatten(),
z_sphere.flatten()], axis=1)
# 缩放和旋转
scaling = np.diag(np.sqrt(eigenvalues))
ellipsoid_points = sphere_points @ scaling @ eigenvectors.T + mean
x_ellipsoid = ellipsoid_points[:, 0].reshape(x_sphere.shape)
y_ellipsoid = ellipsoid_points[:, 1].reshape(y_sphere.shape)
z_ellipsoid = ellipsoid_points[:, 2].reshape(z_sphere.shape)
# 绘制椭球
ax2.plot_surface(x_ellipsoid, y_ellipsoid, z_ellipsoid,
alpha=0.3, color='green', edgecolor='none')
# 绘制数据点
ax2.scatter(X[:, 0], X[:, 1], X[:, 2],
c='blue', alpha=0.2, s=5)
ax2.scatter(mean[0], mean[1], mean[2],
c='red', s=100, marker='x')
# 绘制主轴
for i in range(3):
length = 2 * np.sqrt(eigenvalues[i])
direction = eigenvectors[:, i]
ax2.plot([mean[0], mean[0] + length * direction[0]],
[mean[1], mean[1] + length * direction[1]],
[mean[2], mean[2] + length * direction[2]],
'k-', linewidth=2)
ax2.set_xlabel('X1')
ax2.set_ylabel('X2')
ax2.set_zlabel('X3')
ax2.set_title('Mahalanobis Distance Ellipsoid (1σ)')
# 子图3:切片视图
ax3 = fig.add_subplot(133, projection='3d')
# 计算马氏距离
diff = X - mean
inv_cov = np.linalg.inv(cov)
dist_sq = np.sum(np.dot(diff, inv_cov) * diff, axis=1)
dist = np.sqrt(dist_sq)
# 按距离着色
scatter = ax3.scatter(X[:, 0], X[:, 1], X[:, 2],
c=dist, cmap='viridis',
alpha=0.5, s=20)
ax3.scatter(mean[0], mean[1], mean[2],
c='red', s=100, marker='x')
plt.colorbar(scatter, ax=ax3, label='Mahalanobis Distance',
shrink=0.5, aspect=10)
ax3.set_xlabel('X1')
ax3.set_ylabel('X2')
ax3.set_zlabel('X3')
ax3.set_title('Colored by Distance')
plt.tight_layout()
plt.show()
# 示例使用
mean = [0, 0, 0]
cov = [[2, 1, 0.5],
[1, 3, 1],
[0.5, 1, 1]]
plot_3d_mahalanobis(mean, cov, n_points=1000)左图:数据分布
• 3D散点图
• 红色×表示中心
• 椭球形云团
• 可旋转观察
• 红色×表示中心
• 椭球形云团
• 可旋转观察
中图:等距离椭球
• 1σ椭球表面
• 主轴方向
• 透明度显示内部
• 几何结构清晰
• 主轴方向
• 透明度显示内部
• 几何结构清晰
右图:距离着色
• 颜色表示距离
• 中心近、外围远
• 异常值易识别
• 直观距离感
• 中心近、外围远
• 异常值易识别
• 直观距离感
🎬 动画演示:从欧氏到马氏
通过动画展示如何将椭圆形分布"标准化"为圆形分布。
动画代码
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def animate_standardization():
"""动画展示标准化过程"""
# 生成相关数据
np.random.seed(42)
mean = [0, 0]
cov = [[2, 1.5], [1.5, 1]]
X = np.random.multivariate_normal(mean, cov, 200)
# 计算变换矩阵
eigenvalues, eigenvectors = np.linalg.eigh(cov)
L = eigenvectors @ np.diag(np.sqrt(eigenvalues))
L_inv = np.linalg.inv(L)
# 创建图形
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
def init():
ax1.clear()
ax2.clear()
return []
def update(frame):
t = frame / 100 # 0 到 1
# 插值变换
current_transform = np.eye(2) * (1 - t) + L_inv * t
X_transformed = X @ current_transform.T
# 左图:原始空间
ax1.clear()
ax1.scatter(X[:, 0], X[:, 1], alpha=0.5, s=20)
ax1.scatter(0, 0, c='red', s=100, marker='x', linewidths=3)
ax1.set_xlim(-5, 5)
ax1.set_ylim(-5, 5)
ax1.set_xlabel('X1')
ax1.set_ylabel('X2')
ax1.set_title(f'Original Space (t={t:.2f})')
ax1.grid(True, alpha=0.3)
ax1.axis('equal')
# 绘制椭圆
angle = np.degrees(np.arctan2(eigenvectors[1, 1],
eigenvectors[0, 1]))
width = 2 * np.sqrt(5.99 * eigenvalues[0]) # 95% CI
height = 2 * np.sqrt(5.99 * eigenvalues[1])
from matplotlib.patches import Ellipse
ellipse = Ellipse([0, 0], width, height, angle=angle,
facecolor='none', edgecolor='blue',
linewidth=2, linestyle='--')
ax1.add_patch(ellipse)
# 右图:变换后空间
ax2.clear()
ax2.scatter(X_transformed[:, 0], X_transformed[:, 1],
alpha=0.5, s=20)
ax2.scatter(0, 0, c='red', s=100, marker='x', linewidths=3)
ax2.set_xlim(-5, 5)
ax2.set_ylim(-5, 5)
ax2.set_xlabel('Z1')
ax2.set_ylabel('Z2')
ax2.set_title(f'Transformed Space (t={t:.2f})')
ax2.grid(True, alpha=0.3)
ax2.axis('equal')
# 绘制圆
circle = plt.Circle([0, 0], np.sqrt(5.99),
facecolor='none', edgecolor='green',
linewidth=2, linestyle='--')
ax2.add_patch(circle)
return []
anim = FuncAnimation(fig, update, init_func=init,
frames=101, interval=50, blit=True)
plt.tight_layout()
plt.show()
return anim
# 运行动画
# anim = animate_standardization()
# 保存动画(可选)
# anim.save('mahalanobis_standardization.gif', writer='pillow', fps=20)📽️ 动画过程
• t=0:原始椭圆形分布
• 0<t<1:逐渐变换
• t=1:标准圆形分布
• 变换矩阵:L⁻¹ = Σ⁻¹/²
• 0<t<1:逐渐变换
• t=1:标准圆形分布
• 变换矩阵:L⁻¹ = Σ⁻¹/²
💡 关键洞察
• 椭圆→圆的变换
• 马氏距离=变换后欧氏距离
• 去相关+标准化
• 几何直观理解
• 马氏距离=变换后欧氏距离
• 去相关+标准化
• 几何直观理解
🎨 可视化总结
欧氏距离
• 2D:同心圆
• 3D:同心球
• 特点:各向同性
• 局限:不考虑分布形状
• 3D:同心球
• 特点:各向同性
• 局限:不考虑分布形状
等距离曲线/面
• 欧氏:圆/球
• 马氏:椭圆/椭球
• 关系:椭圆通过Σ⁻¹/²变换为圆
• 本质:自适应度量
• 马氏:椭圆/椭球
• 关系:椭圆通过Σ⁻¹/²变换为圆
• 本质:自适应度量
马氏距离
• 2D:同心椭圆
• 3D:同心椭球
• 特点:各向异性
• 优势:自适应数据分布
• 3D:同心椭球
• 特点:各向异性
• 优势:自适应数据分布
可视化工具
• 静态:椭圆/椭球+热图
• 交互:滑块调整参数
• 动画:变换过程展示
• 3D:旋转观察
• 交互:滑块调整参数
• 动画:变换过程展示
• 3D:旋转观察
🎯 可视化要点
1. 椭圆形状:由协方差矩阵Σ完全决定
2. 主轴方向:对应Σ的特征向量
3. 长短轴比:对应Σ的特征值比
4. 相关性:椭圆倾斜角度反映变量相关程度
5. 等距离:椭圆上所有点到中心马氏距离相同
2. 主轴方向:对应Σ的特征向量
3. 长短轴比:对应Σ的特征值比
4. 相关性:椭圆倾斜角度反映变量相关程度
5. 等距离:椭圆上所有点到中心马氏距离相同
🎯 23.5 关键要点
2D可视化
• 等距离椭圆
• 热图展示
• 对比圆形
• 直观理解
• 热图展示
• 对比圆形
• 直观理解
3D可视化
• 等距离椭球
• 主轴方向
• 距离着色
• 旋转观察
• 主轴方向
• 距离着色
• 旋转观察
交互动画
• 参数调整
• 实时更新
• 变换动画
• 深度理解
• 实时更新
• 变换动画
• 深度理解
💡 核心洞察
• 椭圆的本质:马氏距离的等距离曲线是椭圆,形状由Σ决定
• 变换的视角:通过Σ⁻¹/²变换,椭圆→圆,马氏距离→欧氏距离
• 可视化价值:直观理解相关性、方差、异常值的几何意义
• 实践工具:matplotlib提供完整的2D/3D可视化能力
• 交互学习:通过滑块、动画深化对马氏距离的理解
• 变换的视角:通过Σ⁻¹/²变换,椭圆→圆,马氏距离→欧氏距离
• 可视化价值:直观理解相关性、方差、异常值的几何意义
• 实践工具:matplotlib提供完整的2D/3D可视化能力
• 交互学习:通过滑块、动画深化对马氏距离的理解