马氏距离(Mahalanobis Distance)是度量学习中一种常用的距离指标,同欧氏距离、曼哈顿距离、汉明距离等一样被用作评定数据之间的相似度指标。但却可以应对高维线性分布的数据中各维度间非独立同分布的问题。
从数学上来看,Mahalanobis距离是表示数据的协方差距离。它是一种有效的计算两个未知样本集的相似度的方法。Mahalanobis距离与欧氏距离不同的是它考虑到各种特性之间的联系(例如:一条关于身高的信息会带来一条关于体重的信息,或者关于电脑价格的信息会带来一条关于电脑自带软件的信息,因为两者是有关联的),并且是尺度无关的(scale-invariant),即独立于测量尺度。
为了更好地理解马氏距离,下面列举生活中常见的两个案例:
案例1:坐飞机从上海到北京和坐普快从上海到北京,由于速度的差异,会让人觉得距离也有变化,坐飞机可能觉得,好快啊,没多远,一下就到了,坐火车,时常会感觉好慢,怎么这么远。
案例2:小时候买菜都用杆秤,假如物品和秤砣恰好相等且分别放在秤的两端,那么提纽应该恰好在正中间。但随着物品的重量增大,而秤砣的重量不变,那么这时候,提纽就应该向物品一侧靠近,才能继续保持平衡。马氏距离,就是一个找到两个物体之间平衡点的方法。(说白了就是体现一种杠杆原理的物理过程)
单个数据点的马氏距离
数据点x, y之间的马氏距离(这里的x,y是多维的一个数据集或者向量)
其中Σ是多维随机变量的协方差矩阵,μ为样本均值,如果协方差矩阵是单位向量,也就是各维度独立同分布,马氏距离就变成了欧氏距离。
下面简要说明马氏距离的推导过程:
首先要对数据点进行旋转,旋转至主成分,维度间线性无关,假设新的坐标为
又变换后维度间线性无关且每个维度自己的方差为特征值,所以满足:
马氏距离是旋转变换缩放之后的欧式距离,所以马氏距离的计算公式为:
这就是之前提到的马氏距离的公式。
注意事项:
- 协方差矩阵必须满秩
协方差矩阵里面有求逆矩阵的过程,不满秩不行,要求数据要有原维度个特征值,如果没有可以考虑先进行主成分分析(PCA),因为这种情况下PCA不会损失信息。
- 不能处理非线性流形(manifold)上的问题
只对线性空间有效,如果要处理流形,只能在局部定义,可以用来建立KNN图
Python实现马氏距离的计算:
# encoding: utf-8
#马氏距离的计算:以函数的方式调用
from __future__ import division
import sys
import numpy as np
def mashi_distance(x,y):
print(x)
print(y)
#马氏距离要求样本数要大于维数,否则无法求协方差矩阵
#此处进行转置,表示10个样本,每个样本2维
X=np.vstack([x,y])
print(X)
XT=X.T
print(XT)
#方法一:根据公式求解
S=np.cov(X) #两个维度之间协方差矩阵
SI = np.linalg.inv(S) #协方差矩阵的逆矩阵
#马氏距离计算两个样本之间的距离,此处共有4个样本,两两组合,共有6个距离。
n=XT.shape[0]
d1=[]
for i in range(0,n):
for j in range(i+1,n):
delta=XT[i]-XT[j]
d=np.sqrt(np.dot(np.dot(delta,SI),delta.T))
print(d)
d1.append(d)
if __name__ == '__main__':
# 第一列
x = [3, 5, 2, 8]
# 第二列
y = [4, 6, 2, 4]
mashi_distance(x,y)