要计算两个对象的相似性,有很多种方法可以做相关性分析。
简单的举例几个常用的样本相似性度量方法:
欧式距离(Euclidean Distance)
汉明距离(Hamming Distance)
曼哈顿距离(Manhattan Distance)
余弦相似度(Cosine)
修正余弦相似度(Adjusted Cosine)
皮尔逊相关系数(Pearson)
斯皮尔曼相关系数(Spearman)
1、 欧式距离(Euclidean Distance)
欧式距离全称是欧几里距离,是最易于理解的一种距离计算方式,这里不多介绍。
2、汉明距离(Hamming distance)
汉明距离表示的是两个字符串(相同长度)对应位不同的数量。比如有两个等长的字符串 str1 = “0001” 和 str2 = “0100” 那么它们之间的汉明距离就是2。汉明距离多用于图像像素的匹配(同图搜索)。
3.曼哈顿距离(Manhattan Distance)
想象你在曼哈顿要从一个十字路口开车到另外一个十字路口,那么驾驶的最近距离并不是直线距离,因为你不可能横穿房屋。所以,曼哈顿距离表示的就是你的实际驾驶距离,即两个点在标准坐标系上的绝对轴距总和。
4.余弦相似度(Cosine)
即,高维度上的“余弦夹角”。
夹角越小,余弦值越接近于1,则越正相关;反之趋于-1则负相关。趋于0则不相关。
欧式距离和夹角余弦的区别:
夹角余弦更能反映两者之间的变动趋势,对向量的方向更敏感,对绝对的数值不敏感,而欧式距离较则对数值敏感。
5.修正余弦相似度(Adjusted Cosine)
为什么需要在余弦相似度的基础上使用修正余弦相似度?请看下面这个例子:
有两用户对两个内容评分,按5分制,X和Y两个用户对这两个内容的评分分别为(1,2)和(4,5),使用余弦相似度得到的结果是0.98,两者极为相似。但从评分上看X似乎不喜欢第2个内容,而Y则比较喜欢,余弦相似度对数值的不敏感导致了结果的误差,需要修正这种不合理性就出现了调整余弦相似度,即所有维度上的数值都减去所有评分的均值,比如X和Y的评分均值是(1+2+4+5)/4=3,那么调整后为(-2,-1)和(1,2),再用余弦相似度计算,得到-0.8。
6、皮尔逊相关系数(Pearson Correlation Coefficient)
皮尔逊相关系数公式实际上就是在计算夹角余弦之前将两个向量减去各个样本的平均值,达到中心化的目的。皮尔逊相关函数是余弦相似度在维度缺失上面的一种改进方法。
7.斯皮尔曼相关系数(Spearman)
斯皮尔曼相关系数被定义成等级变量之间的皮尔逊相关系数。注意:当变量的两个值相同时,它们的排行是通过对它们位置进行平均而得到的。
例如:
有变量A =(10,8.9,4.5,4.5,2,0.6),其对应按降序的等级变量是xi=(6,5,3.5,3.5,2,1)。变量B =(4,28.1,8,7.5,2.9,5),其对应按降序的等级变量是yi=(5,1,2,3,6,4)。
它是衡量两个变量的依赖性的 非参数 指标。 它利用单调方程评价两个统计变量的相关性。 如果数据中没有重复值, 并且当两个变量完全单调相关时,斯皮尔曼相关系数则为+1或−1。
总结:
其他相关参考:
对应C++代码:
bool Cosine(double* A, double* B, V3DLONG Length, double &similarity)
{//余弦相似度
// similarity 相关性
// 0.8-1.0 极强相关
// 0.6-0.8 强相关
// 0.4-0.6 中等程度相关
// 0.2-0.4 弱相关
// 0.0-0.2 极弱相关或无相关
//计算相关系数
double R1(0), R2(0), R3(0);
for (long i = 0; i < Length; i++)
{
R1 += A[i] * B[i];
R2 += pow(A[i], 2);
R3 += pow(B[i], 2);
}
similarity = R1 / sqrt(R2*R3);
return true;
}
bool AdjustedCosine(double* A, double* B, V3DLONG Length, double &similarity)
{//修正余弦相似度
// similarity 相关性
// 0.8-1.0 极强相关
// 0.6-0.8 强相关
// 0.4-0.6 中等程度相关
// 0.2-0.4 弱相关
// 0.0-0.2 极弱相关或无相关
double sum(0.0), ave(0.0);
//求和
for(int i=0; i<Length; i++){sum+=A[i];}
for(int i=0; i<Length; i++){sum+=B[i];}
//求平均值
ave = sum / double(Length*2);
//计算相关系数
double R1(0), R2(0), R3(0);
for (long i = 0; i < Length; i++)
{
R1 += (A[i] - ave) * (B[i] - ave);
R2 += pow((A[i] - ave), 2);
R3 += pow((B[i] - ave), 2);
}
similarity = R1 / sqrt(R2*R3);
return true;
}
bool Pearson(double* A, double* B, V3DLONG Length, double &similarity)
{//皮尔逊相关系数
// similarity 相关性
// 0.8-1.0 极强相关
// 0.6-0.8 强相关
// 0.4-0.6 中等程度相关
// 0.2-0.4 弱相关
// 0.0-0.2 极弱相关或无相关
double sumA(0.0), sumB(0.0), aveA(0.0), aveB(0.0);
//求和
for(int i=0; i<Length; i++){sumA+=A[i];}
for(int i=0; i<Length; i++){sumB+=B[i];}
//求平均值
aveA = sumA / double(Length);
aveB = sumB / double(Length);
//计算相关系数
double R1(0), R2(0), R3(0);
for (long i = 0; i < Length; i++)
{
R1 += (A[i] - aveA) * (B[i] - aveB);
R2 += pow((A[i] - aveA), 2);
R3 += pow((B[i] - aveB), 2);
}
similarity = R1 / sqrt(R2*R3);
return true;
}
bool SpearmanLevel(double* A, V3DLONG Length, vector<double> &level)
{//先冒泡排序,对应等级为1~Length,再检查重复值,将其等级修改为平均等级
double* sortedA = new double[Length];
for (V3DLONG i = 0; i < Length; i++) {sortedA[i] = A[i];}
level.clear();
for (V3DLONG i = 0; i < Length; i++) {level.push_back(i+1);}
for (V3DLONG i = 0; i < Length - 1; i++)
{
for (V3DLONG j = 0; j < Length - 1 - i; j++)
{
if (sortedA[j] > sortedA[j+1]) // 相邻元素两两对比
{
double temp = sortedA[j+1]; // 元素交换
sortedA[j+1] = sortedA[j];
sortedA[j] = temp;
}
}
}
//排序已完成,开始检查是否有相同的数组元素,如果有,则其索引变为对应索引均值
double tmp_sum_level = 0; V3DLONG count_repeat = 0;
for (V3DLONG i = 1; i < Length; i++)
{
if(sortedA[i] == sortedA[i-1])
{
tmp_sum_level += level[i-1];
count_repeat++;
}
else
{
if(count_repeat>0)
{
tmp_sum_level += level[i];
double tmp_ave_level = tmp_sum_level/(count_repeat+1);
for(V3DLONG j=i; j>i-(count_repeat+1); j--)
{ level[j] = tmp_ave_level; }
count_repeat = 0; tmp_sum_level = 0;
}
}
if((i==Length-1)&&(count_repeat>0))
{
tmp_sum_level += level[i];
double tmp_ave_level = tmp_sum_level/(count_repeat+1);
for(V3DLONG j=i; j>i-(count_repeat+1); j--)
{ level[j] = tmp_ave_level; }
}
}
if(sortedA){delete []sortedA; sortedA=NULL;}
return true;
}
bool Spearman(double* A, double* B, V3DLONG Length, double &similarity)
{//斯皮尔曼相关系数
// similarity 相关性
// 0.8-1.0 极强相关
// 0.6-0.8 强相关
// 0.4-0.6 中等程度相关
// 0.2-0.4 弱相关
// 0.0-0.2 极弱相关或无相关
vector<double> levelA, levelB;
SpearmanLevel(A,Length,levelA); SpearmanLevel(B,Length,levelB);
double sumA(0.0), sumB(0.0), aveA(0.0), aveB(0.0);
//求和
for(int i=0; i<Length; i++){sumA+=levelA[i];}
for(int i=0; i<Length; i++){sumB+=levelB[i];}
//求平均值
aveA = sumA / double(Length);
aveB = sumB / double(Length);
//计算相关系数
double R1(0), R2(0), R3(0);
for (long i = 0; i < Length; i++)
{
R1 += (levelA[i] - aveA) * (levelB[i] - aveB);
R2 += pow((levelA[i] - aveA), 2);
R3 += pow((levelB[i] - aveB), 2);
}
similarity = R1 / sqrt(R2*R3);
return true;
}