首先是一段计算三个相似度的Python代码。
需要注意的是,进行归一化操作后,三个函数取值范围都是0-1,而且都是数值越大表示相似性越高,数值为1代表完全相似。
import numpy as np def EuclideanDistance(dataA,dataB): '''【目的】计算欧氏距离(对应值的差平方之和再开方),注重数据之间的绝对位置而不是方向 【输入】np.array 【输出】已进行归一化,取值(0,1],数值越大表示相似性越高,数值为1代表完全相似''' #np.linalg.norm用于范数计算,默认二范数,相当于平方和开根号 #归一化到(0,1]区间:1/(1+原始值) return 1/(1+np.linalg.norm(dataA-dataB)) def CosineDistance(dataA,dataB): '''【目的】计算余弦相似度,注重数据的方向而非绝对位置 【输入】np.array 【输出】已进行归一化,取值[0,1],数值越大表示相似性越高,数值为1代表完全相似''' sumData=np.dot(dataA,dataB)#公式中的分子,向量的内积 #np.linalg.norm用于范数计算,默认二范数,相当于平方和开根号 denom=np.linalg.norm(dataA)*np.linalg.norm(dataB)#公式中的分母 #归一化到[0,1]区间:0.5 + 0.5 * 原始值 return 0.5+0.5*(sumData/denom) def Jaccard(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欧氏距离:',EuclideanDistance(x1,x2)) print('\n余弦相似度:',CosineDistance(x1,x2)) print('\nJaccard相似度:',Jaccard(x1,x2))
完全相同的情况下,三个相似度结果都是1代表完全相似 欧氏距离: 1.0 余弦相似度: 1.0 Jaccard相似度: 1.0
例2:
#注意,直接用列表list不能实现一一对应相加,需要用np的数组array x1 = np.array([1,1]) x2 = np.array([300,300]) print('绝对位置远,欧式相似度低;方向一样,则余弦接近1代表完全相似;无相同元素,Jaccard相似度为0') print('\n欧氏距离:',EuclideanDistance(x1,x2)) print('\n余弦相似度:',CosineDistance(x1,x2)) print('\nJaccard相似度:',Jaccard(x1,x2))
绝对位置远,欧式相似度低;方向一样,则余弦接近1代表完全相似;无相同元素,Jaccard相似度为0 欧氏距离: 0.0023593260392814103 余弦相似度: 0.9999999999999999 Jaccard相似度: 0.0
例3:
x1 = np.array([0.01,0.02]) x2 = np.array([-0.01,-0.02]) print('绝对位置很接近,欧氏相似性很高接近1;方向完全相反,余弦相似度为0代表完全不相似;无相同元素,Jaccard相似度为0') print('\n欧氏距离:',EuclideanDistance(x1,x2)) print('\n余弦相似度:',CosineDistance(x1,x2)) print('\nJaccard相似度:',Jaccard(x1,x2))
绝对位置很接近,欧氏相似性很高接近1;方向完全相反,余弦相似度为0代表完全不相似;无相同元素,Jaccard相似度为0 欧氏距离: 0.9571930265030102 余弦相似度: 0.0 Jaccard相似度: 0.0
附:本文计算三个相似度的核心代码参考《机器学习算法竞赛实战》。