一、 欧式距离
欧氏距离是最常见的距离度量,衡量的是多维空间中点之间的绝对距离。
1.手动输入数组中数据个数,保证了数组中数据数量相同,所以没有再次进行数量判断,在实际应用时,如果是读取的数据,则应该进行数量是否相等的判断。
2.定义一个距离判断的类,在类的构造函数中调用距离计算的成员函数。
- 实现方式1
#include<iostream>
#include<cmath>
using namespace std;
class Distance{
public:
Distance(int m,double array1[],double array2[]);//Distance(int m,double* array1,double* array2)
~Distance(){}
void distance(double a[],double b[]);//void distance(double* a,double* b)
void set(double array1[],double array2[]);//void set(double* a,double* b)
double get();
private:
int n;
double* a;//声明两个对象
double* b;
double square;
double Result;// 欧氏距离计算结果
};
Distance::Distance(int m,double array1[],double array2[]){//
n=m;
set(array1,array2);
distance(a,b);
}
void Distance::set(double array1[],double array2[]){
a=array1;
b=array2;
}
void Distance::distance(double a[],double b[]){
square=0;
for(int i=0;i<n;i++){
square+=(a[i]-b[i])*(a[i]-b[i]);
}
Result=sqrt(square);
}
double Distance::get(){
return Result;
}
//主函数
int main(){
int n;
cout<<"Please input the dimensions n:";//输入维数
cin>>n;
double a[n];//声明一个n维的double类型的数组a
double b[n];//声明一个n维的double类型的数组b
cout<<"Input the "<<n<<" number for the dimendions of a1:";
for(int i=0;i<n;i++)
cin>>a[i];
cout<<"Input the "<<n<<" number for the dimendions of b1:";
for(int i=0;i<n;i++)
cin>>b[i];
Distance distance(n,a,b);//实例化对象distance
cout<<"The distance is:"<<distance.get()<<endl;
return 0;
}
- 实现方式2
#include <iostream>
#include<iostream>
#include<cmath>
using namespace std;
class Distance{
public:
Distance(int m,double* array1,double* array2);
~Distance(){}
void distance(double* a,double* b);
double get();
private:
int n;
double* a;//声明两个对象
double* b;
double square;
double Result;//欧氏距离计算结果
};
Distance::Distance(int m,double* array1,double* array2){
n=m;
a=array1;
b=array2;
distance(a,b);
}
void Distance::distance(double *a,double *b){
square=0;
for(int i=0;i<n;i++){
square+=(a[i]-b[i])*(a[i]-b[i]);
}
Result=sqrt(square);
}
double Distance::get(){
return Result;
}
//主函数
int main(){
int n;
cout<<"Please input the dimensions n:";//输入维数
cin>>n;
double a[n];//声明一个n维的double类型的数组a
double b[n];//声明一个n维的double类型的数组b
cout<<"Input the "<<n<<" number for the dimendions of a1:";
for(int i=0;i<n;i++)
cin>>a[i];
cout<<"Input the "<<n<<" number for the dimendions of b1:";
for(int i=0;i<n;i++)
cin>>b[i];
Distance distance(n,a,b);//实例化对象distance
cout<<"The distance is:"<<distance.get()<<endl;
return 0;
}
二、 标准化的欧式距离
引入标准化欧式距离的原因是一个数据xi的各个维度之间的尺度不一样。比如v1=(100,10),v2 = (500,40),则计算欧式距离会压制第二维度的影响力。
标准欧氏距离的思路:数据各维分量的分布不一样,可以先将各个分量都“标准化”到均值、方差相等。
如果将方差的倒数看成是一个权重,这个公式可以看成是一种加权欧氏距离。
如上图,求两组数据xi和yi的标准欧式距离,其中si是每个维度上的标准差。
其求解步骤为:
(1)分别求取xi和yi在每个维度上的平均值,假设为ui;
(2)求解si × si: ( (xi-ui)×(xi-ui) + (yi-ui)×(yi-ui) ) / 2 ;
(3)1/(si × si)相当于欧式距离算法中添加的权重。
编程时,只需要另求解平均值、标准差,其他的像欧式距离求解即可。
三、 余弦相似度
这个基本上是最常用的,最初用在计算文本相似度效果很好,一般像tf-idf一下然后计算,推荐中在协同过滤以及很多算法中都比其他相似度效果理想。
虽然余弦相似度对个体间存在的偏见可以进行一定的修正,但是因为只能分辨个体在维之间的差异,没法衡量每个维数值的差异,会导致这样一个情况: 比如用户对内容评分,5分制,X和Y两个用户对两个内容的评分分别为(1,2)和(4,5),使用余弦相似度得出的结果是0.98,两者极为相似,但从评分上看X似乎不喜欢这2个内容,而Y比较喜欢,余弦相似度对数值的不敏感导致了结果的误差,需要修正这种不合理性,采用所有维度上的数值都减去一个均值,比如X和Y的评分均值都是3,那么调整后为(-2,-1)和(1,2),再用余弦相似度计算,得到-0.8,相似度为负值并且差异不小,但更加符合现实。
所以有时候也关心距离上的差异会先对每个值都减去一个均值,这样称为调整余弦相似度。
- 实现方式1
#include <iostream>
#include<cmath>
using namespace std;
class Distance{
public:
Distance(int m,double array1[],double array2[]);
~Distance(){}
void distance(double a[],double b[]);//计算欧式距离实现部分
void set(double array1[],double array2[]);
double getM(double c[]);//获得公式分母
double get();
private:
int n;
double* a;//声明两个对象
double* b;
double s1;
double s2;
double s3;
double Result;// 欧氏距离计算结果
};
Distance::Distance(int m,double array1[],double array2[]){//
n=m;
a=array1;
b=array2;
set(array1,array2);
distance(a,b);
}
double Distance::getM(double c[]){
s1=0;
for(int i=0;i<n;i++){
s1+=c[i]*c[i];
}
return sqrt(s1);
}
void Distance::distance(double a[],double b[]){
s2=0;
s3=0;
for(int i=0;i<n;i++){
s2+=a[i]*b[i];
}
s3=getM(a)*getM(b);
Result=sqrt(s2/s3);
}
double Distance::get(){
return Result;
}
//主函数
int main(){
int n;
cout<<"Please input the dimensions n:";//输入维数
cin>>n;
double a[n];//声明一个n维的double类型的数组a
double b[n];//声明一个n维的double类型的数组b
cout<<"Input the "<<n<<" number for the dimendions of a1:";
for(int i=0;i<n;i++)
cin>>a[i];
cout<<"Input the "<<n<<" number for the dimendions of b1:";
for(int i=0;i<n;i++)
cin>>b[i];
Distance distance(n,a,b);//实例化对象distance
cout<<"The distance is:"<<distance.get()<<endl;
return 0;
}
- 实现方式2
#include <iostream>
#include<cmath>
using namespace std;
class Distance{
public:
Distance(int m,double array1[],double array2[]);
~Distance(){}
void distance(double a[],double b[]);//计算欧式距离实现部分
double get();
private:
int n;
double* a;//声明两个对象
double* b;
double s2;
double s3;
double s4;
double Result;// 欧氏距离计算结果
};
Distance::Distance(int m,double array1[],double array2[]){//
n=m;
a=array1;
b=array2;
distance(a,b);
}
void Distance::distance(double a[],double b[]){
s2=0;
s3=0;
Result=0;
for(int i=0;i<n;i++){
s2+=a[i]*b[i];//分母计算
s3+=a[i]*a[i];//分子计算
s4+=b[i]*b[i];//分子计算
}
s3=sqrt(s3);
s4=sqrt(s4);
if(s3!=0 && s4!=0)//因为是分母,所以判断是否为零
Result=s2/(s3*s4);
}
double Distance::get(){
return Result;
}
//主函数
int main(){
int n;
cout<<"Please input the dimensions n:";//输入维数
cin>>n;
double a[n];//声明一个n维的double类型的数组a
double b[n];//声明一个n维的double类型的数组b
cout<<"Input the "<<n<<" number for the dimendions of a1:";
for(int i=0;i<n;i++)
cin>>a[i];
cout<<"Input the "<<n<<" number for the dimendions of b1:";
for(int i=0;i<n;i++)
cin>>b[i];
Distance distance(n,a,b);//实例化对象distance
cout<<"The distance is:"<<distance.get()<<endl;
return 0;
}
欧式距离和余弦相似度的区别:
根据欧氏距离和余弦相似度各自的计算方式和衡量特征,适用于不同的数据分析模型:欧氏距离能够体现个体数值特征的绝对差异,所以更多的用于需要从维度的数值大小中体现差异的分析,如使用用户行为指标分析用户价值的相似度或差异;而余弦相似度更多的是从方向上区分差异,而对绝对的数值不敏感, 更多的用于使用用户对内容评分来区分用户兴趣的相似度和差异,同时修正了用户间可能存在的度量标准不统一的问题。
四、 马氏距离
欧几里得距离无法忽略指标度量的差异,所以在使用欧氏距离之前需要对底层指标进行数据的标准化,而基于各指标维度进行标准化后再使用欧氏距离就衍生出来另外一个距离度量——马哈拉诺比斯距离(Mahalanobis Distance),简称马氏距离。
五、 曼哈顿距离
其中,p是I的维度。(通俗的讲,就是每个维度的数据做差,求绝对值,并相加。)
因为并未打算用该方式,且实现较简单,因此不在此记录实现程序。