马氏距离 Mahalanobis distance
基本介绍
马氏距离(Mahalanobis distance)是由印度统计学家马哈拉诺比斯(P. C. Mahalanobis)提出的,表示点与一个分布之间的距离。
它是一种有效的计算两个未知样本集的相似度的方法。
与欧氏距离不同的是,它考虑到各种特性之间的联系(例如:一条关于身高的信息会带来一条关于体重的信息,因为两者是有关联的),并且是尺度无关的(scale-invariant),即独立于测量尺度。
马氏距离(Mahalanobis Distance)是一种距离的度量,可以看作是欧氏距离的一种修正,修正了欧式距离中各个维度尺度不一致且相关的问题。
对于一个均值为μ,协方差矩阵为Σ的多维向量x,其马氏距离为:
单个数据点的马氏距离:
$$ D_M(x) = \sqrt{ (x-μ)^TΣ^{-1}(x-μ) } $$
数据点x, y之间的马氏距离
$$ \sqrt{ (x-y)^TΣ^{-1}(x-y) } $$
其中Σ是多维随机变量的协方差矩阵,μ为样本均值,如果协方差矩阵是单位向量,也就是各维度独立同分布,马氏距离就变成了欧氏距离。
马氏距离与欧氏距离的区别图:
在下面两张图中,是同一个数据分布。
左图中距离中心点 $\mu$ 距离相同的两个点和A 和 B ,在欧式距离的意义下,距离中心是等距离的
右图中距离中心点 $\mu$ 距离不相同的两个点和A 和 B ,在马氏距离的意义下,距离中心是等距离的,它考虑了数据分布
简单的举例说明考虑数据分布的重要性:
假如一个分布是一个打靶的数据结果,坐标系的原点不是在靶子中心而是在靶子的左下角,那么按理说打出的靶子数据一般是一个位于第一象限的圆形。
但是现在我强行把x2维度的单位设置为米,而x1维度的单位设置为厘米,那么数据分布是不是就变成扁了的圆形。
本来当数据的单位设置的恰当的时候,我们使用欧式距离就可以很好的测量,一个运动员这一靶打的好不好,测量打靶位置距离靶中心的距离即可。
但是当数据的单位设置的不恰当的时候,我们继续使用欧式距离去测量,可以发现本来距离中心点O同等距离的A和B两点,现在距离中心O的距离不同了,从实际的打靶意义来说,你能说B这一靶打的不如A好吗?显然不合理。所以这里使用马氏距离,在考虑数据分布的情况下来评价A和B这两靶,就更合理了。
这个马氏距离十分适合评价用神经网络提取的目标特征之间的相似度。因为神经网络提取的特征向量也是有它独特的数据分布的,仅仅使用欧式距离,有可能同一类中的目标,却有着较大的欧式距离,而不同类却可能有着较小的欧式距离,此时使用欧式距离来评价目标之间的相似度显然不如使用考虑了数据分布的马氏距离来的好。
公式中的协方差矩阵是需要求逆矩阵的,那么就要求协方差矩阵需要是满秩矩阵。
numpy代码:
import numpy as np
def get_sample():
# sample = [
# [0,2],
# [0,4],
# [0,-2],
# [0,-4],
# [-8,0],
# [-4,0],
# [8, 0],
# [4, 0],
# ]
sample = [
[0, 2],
[0, -2],
[-4, 0],
[4, 0],
]
return sample
def calc_Mahalanobis_distracne(covariance, x, y):
x = np.array(x)
y = np.array(y)
covariance = np.array(covariance)
dis = (x-y)@np.linalg.inv(covariance)@(x-y).T
dis = np.sqrt(dis)
return dis
def calc_Covariance(sample_matrix):
covariance = np.cov(sample_matrix, rowvar=False)
return covariance
if __name__ == '__main__':
sample = get_sample()
covariance = calc_Covariance(sample_matrix=sample)
origin = [0,0]
x1 = [4,0]
x2 = [0,2]
dis1 = calc_Mahalanobis_distracne(covariance, origin, x1)
dis2 = calc_Mahalanobis_distracne(covariance, origin, x2)
print(dis1)
print(dis2)
结果:
1.224744871391589
1.224744871391589