python实现相似性/距离的度量

L1 绝对值/曼哈顿距离

从名字就可以猜出这种距离的计算方法了。想象你在曼哈顿要从一个十字路口开车到另外一个十字路口,驾驶距离是两点间的直线距离吗?显然不是,除非你能穿越大楼。实际驾驶距离就是这个“曼哈顿距离”(L1范数)。而这也是曼哈顿距离名称的来源,曼哈顿距离也称为城市街区距离(City Block distance)


import numpy as np

def manhattan_dist(p, q):
    ''' 
    曼哈顿距离/绝对距离(L1范数)
    INPUT  -> 长度一致的向量1、向量2
    举例: p = [1,2,6]; q = [1,3,5]
    '''
    p = np.mat(p)
    q = np.mat(q)
    # return np.linalg.norm(p-q, ord=1)
    return np.sum(np.abs(p-q))

p = [1,3,2,3,4,3]
q = [1,3,4,3,2,3]
print(manhattan_dist(p,q))

L2 欧氏距离

欧氏距离(L2范数)是最易于理解的一种距离计算方法,源自欧氏空间中两点间的距离公式


def euclidean_dist(p, q):
    ''' 
    欧式距离(L2范数)
    INPUT  -> 长度一致的向量1、向量2
    '''
    p = np.mat(p)
    q = np.mat(q)
    # return math.sqrt(np.sum(np.square(p-q)))
    # return np.linalg.norm(p-q)
    return math.sqrt(np.sum(np.power(p-q, 2))) 

def euclidean_dist_2(p, q):
    ''' 
    坐标点间欧式距离(速度快)
    INPUT  -> 坐标1、坐标2
    '''
    return math.sqrt(math.pow(p[0]-q[0], 2)+math.pow(p[1]-q[1], 2))

def standardized_euclidean_dist(p, q):
    ''' 
    标准化欧式距离
    INPUT  -> 长度一致的向量1、向量2
    '''
    sumnum = 0
    for i in range(len(p)):
        # 计算si 分量标准差
        avg = (p[i]-q[i])/2
        si = math.sqrt((p[i]-avg)**2+(q[i]-avg)**2)
        sumnum += ((p[i]-q[i])/si )**2
    return math.sqrt(sumnum)

L-∞ 切比雪夫距离

国际象棋玩过么?国王走一步能够移动到相邻的8个方格中的任意一个(如下图)。那么国王从格子(x1,y1)走到格子(x2,y2)最少需要多少步?自己走走试试。你会发现最少步数总是max(| x2-x1| , |y2-y1| ) 步。有一种类似的一种距离度量方法叫切比雪夫距离(L∞范数)
很少用到。


def chebyshev_dist(p, q):
    ''' 
    切比雪夫距离(L-∞范数)
    INPUT  -> 长度一致的向量1、向量2
    '''
    p = np.mat(p)
    q = np.mat(q)
    # return np.abs(p-q).max()
    # return np.linalg.norm(p-q, ord=np.inf)
    return np.max(np.abs(p-q))

汉明距离

两个等长字符串s1与s2之间的汉明距离定义为将其中一个变为另外一个所需要作的最小替换次数。例如字符串“1111”与“1001”之间的汉明距离为2。
应用:信息编码(为了增强容错性,应使得编码间的最小汉明距离尽可能大)

def hanming_dist(p, q):
    ''' 
    汉明距离
    INPUT  -> 长度一致的向量1、向量2
    '''
    p = np.mat(p)
    q = np.mat(q)
    smstr = np.nonzero(p-q)
    return np.shape(smstr)[1]

杰卡德相似系数/杰卡德距离

当数据集为二元变量时,我们只有两种状态:0或者1。这个时候以上的计算相似度的方法就无法派上用场,于是我们引出Jaccard系数,这是一个能够表示两个数据集都是二元变量(也可以多元)的相似度的指标
杰卡德相似系数表示为



即两个样本的特征集合A和B的交集元素在A和B的并集中所占的比例。杰卡德相似系数越大,两个样本的相似性越大。
杰卡德距离(Jaccard Distance) 是用来衡量两个集合差异性的一种指标,它是杰卡德相似系数的补集,被定义为1减去Jaccard相似系数。

def jaccard_sim(p, q):
    ''' 
    计算两个向量的杰卡德相似系数
    INPUT  -> 长度一致的向量1、向量2
    '''
    set_p = set(p)
    set_q = set(q)
    sim = float(len(set_p & set_q))/ len(set_p | set_q)
    return sim

def jaccard_dist(p, q):
    ''' 
    计算两个向量的杰卡德距离
    INPUT  -> 长度一致的向量1、向量2
    '''
    set_p = set(p)
    set_q = set(q)
    dis = float(len((set_p | set_q)-(set_p & set_q)))/ len(set_p | set_q)
    # dis = pdist([p, q],'jaccard')
    return dis

余弦夹角相似度/余弦距离

余弦距离,也称为余弦相似度,是用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小的度量。
几何中夹角余弦可用来衡量两个向量方向的差异,机器学习中借用这一概念来衡量样本向量之间的差异
夹角余弦取值范围为[-1,1]。夹角余弦越大表示两个向量的夹角越小,夹角余弦越小表示两向量的夹角越大。当两个向量的方向重合时夹角余弦取最大值1,当两个向量的方向完全相反夹角余弦取最小值-1。


def cosin_dist(p, q):
    ''' 
    计算两个向量的余弦距离
    INPUT  -> 长度一致的向量1、向量2
    '''
    # return 1-np.dot(p,q)/(np.linalg.norm(p)*(np.linalg.norm(q)))
    return pdist(np.vstack([p, q]), 'cosine')[0]

推荐阅读更多精彩内容