欧氏距离、余弦相似度、Jaccard相似度、皮尔逊的Python代码与实例

首先是一段计算4个相似度的Python代码。

需要注意的是,进行归一化操作后,4个函数取值范围都是0-1,而且都是数值越大表示相似性越高,数值为1代表完全相似。

import numpy as np

def CalSimEuD(dataA,dataB):
    '''【目的】计算欧氏距离(对应值的差平方之和再开方),注重数据之间的绝对位置而不是方向
       【输入】np.array
       【输出】已进行归一化,取值(0,1],数值越大表示相似性越高,数值为1代表完全相似'''
    #np.linalg.norm用于范数计算,默认二范数,相当于平方和开根号
    #原始取值为(0,正无穷),归一化到(0,1]区间:1/(1+原始值)
    return 1/(1+np.linalg.norm(dataA-dataB))

def CalSimCosine(dataA,dataB):
    '''【目的】计算余弦相似度,注重数据的方向而非绝对位置
       【输入】np.array
       【输出】已进行归一化,取值[0,1],数值越大表示相似性越高,数值为1代表完全相似'''
    sumData=np.dot(dataA,dataB)#公式中的分子,向量的内积
    #np.linalg.norm用于范数计算,默认二范数,相当于平方和开根号
    denom=np.linalg.norm(dataA)*np.linalg.norm(dataB)#公式中的分母
    #原始取值为[-1,1],归一化到[0,1]区间:0.5 + 0.5 * 原始值
    return 0.5+0.5*(sumData/denom)

def CalSimPearson(dataA,dataB):
    '''【目的】计算皮尔逊相关系数,是对余弦相似度的修正,分子和分母都需要减去输入数据集各自本身向量的均值,以达到中心化
       【输入】np.array,不可以输入常量数组如[1,1]
       【输出】已进行归一化,取值[0,1],数值越大表示相似性越高,数值为1代表完全相似'''
    # np直接计算出的皮尔逊相关系数取值范围[-1,1],归一化到[0,1]区间:0.5 + 0.5 * 原始值
    return 0.5 + 0.5 * np.corrcoef(dataA,dataB,rowvar = 0)[0][1]

def CalSimJaccard(dataA,dataB):
    '''【目的】计算Jaccard相似度,度量集合之间的差异,共有的元素越多则越相似
       【输入】np.array
       【输出】取值[0,1],数值越大表示相似性越高,数值为1代表完全相似'''
    A_len,B_len=len(dataA),len(dataB)
    C=[i for i in dataA if i in dataB]#取交集
    C_len=len(C)#交集含有元素的个数
    return C_len/(A_len+B_len-C_len)

然后举三个例子。

例1:

x1 = np.array([1,2,3])
x2 = np.array([1,2,3])
print('完全相同的情况下,三个相似度结果都是1代表完全相似')
print('\n欧氏距离:',CalSimEuD(x1,x2))
print('\n余弦相似度:',CalSimCosine(x1,x2))
print('\n皮尔逊(归一化版):',CalSimPearson(x1,x2))
print('\nJaccard相似度:',CalSimJaccard(x1,x2))
完全相同的情况下,三个相似度结果都是1代表完全相似

欧氏距离: 1.0

余弦相似度: 1.0

皮尔逊(归一化版): 1.0

Jaccard相似度: 1.0

例2:

#注意,直接用列表list不能实现一一对应相加,需要用np的数组array
x1 = np.array([1,2])
x2 = np.array([300,600])
print('''绝对位置远,欧式相似度低;
         方向一样,则余弦1代表完全相似;
         方向一样,则皮尔逊1代表完全相似;
         无相同元素,Jaccard相似度为0''')
print('\n欧氏距离:',CalSimEuD(x1,x2))
print('\n余弦相似度:',CalSimCosine(x1,x2))
print('\n皮尔逊(归一化版):',CalSimPearson(x1,x2))
print('\nJaccard相似度:',CalSimJaccard(x1,x2))
绝对位置远,欧式相似度低;
         方向一样,则余弦1代表完全相似;
         方向一样,则皮尔逊1代表完全相似;
         无相同元素,Jaccard相似度为0

欧氏距离: 0.0014934638734159808

余弦相似度: 1.0

皮尔逊: 1.0

Jaccard相似度: 0.0

例3:

x1 = np.array([0.01,0.02])
x2 = np.array([-0.01,-0.02])
print('''绝对位置很接近,欧氏相似性很高接近1;
         方向完全相反,余弦相似度为0代表完全不相似;
         方向完全相反,皮尔逊为0代表完全不相似;
         无相同元素,Jaccard相似度为0''')
print('\n欧氏距离:',CalSimEuD(x1,x2))
print('\n余弦相似度:',CalSimCosine(x1,x2))
print('\n皮尔逊(归一化版):',CalSimPearson(x1,x2))
print('\nJaccard相似度:',CalSimJaccard(x1,x2))
绝对位置很接近,欧氏相似性很高接近1;
         方向完全相反,余弦相似度为0代表完全不相似;
         方向完全相反,皮尔逊为0代表完全不相似;
         无相同元素,Jaccard相似度为0

欧氏距离: 0.9571930265030102

余弦相似度: 0.0

皮尔逊: 0.0

Jaccard相似度: 0.0

通过上面的例子可以看到,皮尔逊和余弦相似性的结果比较接近,注重的是向量的方向。

欧氏距离注重的是两个向量绝对位置的差异。

Jaccard注重的是两个向量内部完全相同元素的比例。

除此之外,还有调整余弦相似性,和皮尔逊比较相似,但是去中心化方式有所差异。

附:本文计算相似度的核心代码部分参考《机器学习算法竞赛实战》。 

你可能感兴趣的:(机器学习,python,机器学习)