距离与相似性
数值点距离:numeric data points Numeric Data Points
闵可夫斯基距离
闵可夫斯基距离

那么,闵可夫斯基距离定义为:

该距离最常用的

绿色的斜线表示欧几里得距离,在现实中是不可能的。其他三条折线表示了曼哈顿距离,这三条折线的长度是相等的。
当

我们知道平面上到原点欧几里得距离

注意,当 p < 1
时,闵可夫斯基距离不再符合三角形法则,举个例子:当<
(1+1)^{1/p} > 2
闵可夫斯基距离比较直观,但是它与数据的分布无关,具有一定的局限性,如果
: 该维度上的均值
: 该维度上的标准差
可以看到,上述处理开始体现数据的统计特性了。这种方法在假设数据各个维度不相关的情况下利用数据分布的特性计算出不同的距离。如果维度相互之间数据相关
马氏距离
考虑下面这张图,椭圆表示等高线,从欧几里得的距离来算,绿黑距离大于红黑距离,但是从马氏距离,结果恰好相反:

马氏距离实际上是利用

下图蓝色表示原样本点的分布,两颗红星坐标分别是

由于

将上面两个图的绘制代码和求马氏距离的代码贴在这里,以备以后查阅:
# -*- coding=utf-8 -*-
# code related at: http://www.cnblogs.com/daniel-D/
import numpy as np
import pylab as pl
import scipy.spatial.distance as dist
def plotSamples(x, y, z=None):
stars = np.matrix([[3., -2., 0.], [3., 2., 0.]])
if z is not None:
x, y = z * np.matrix([x, y])
stars = z * stars
pl.scatter(x, y, s=10) # 画 gaussian 随机点
pl.scatter(np.array(stars[0]), np.array(stars[1]), s=200, marker='*', color='r') # 画三个指定点
pl.axhline(linewidth=2, color='g') # 画 x 轴
pl.axvline(linewidth=2, color='g') # 画 y 轴
pl.axis('equal')
pl.axis([-5, 5, -5, 5])
pl.show()
# 产生高斯分布的随机点
mean = [0, 0] # 平均值
cov = [[2, 1], [1, 2]] # 协方差
x, y = np.random.multivariate_normal(mean, cov, 1000).T
plotSamples(x, y)
covMat = np.matrix(np.cov(x, y)) # 求 x 与 y 的协方差矩阵
Z = np.linalg.cholesky(covMat).I # 仿射矩阵
plotSamples(x, y, Z)
# 求马氏距离
print '\n到原点的马氏距离分别是:'
print dist.mahalanobis([0,0], [3,3], covMat.I), dist.mahalanobis([0,0], [-2,2], covMat.I)
# 求变换后的欧几里得距离
dots = (Z * np.matrix([[3, -2, 0], [3, 2, 0]])).T
print '\n变换后到原点的欧几里得距离分别是:'
print dist.minkowski([0, 0], np.array(dots[0]), 2), dist.minkowski([0, 0], np.array(dots[1]), 2)
马氏距离的变换和
类别点距离(categorical data points)
$distance_{final} = α.distance_{numeric} + (1- α).distance_{categorical}$
汉明距离
汉明距离

还可以用简单的匹配系数来表示两点之间的相似度——匹配字符数
Jacard 相似度

分子是集合交集,分母是集合并集,画个图,马上就明白咋回事了。
和

向量内积
向量内积是线性代数里最为常见的计算,实际上它还是一种有效并且直观的相似性测量手段。向量内积的定义如下:
直观的解释是:如果[-1, 1]
两个函数之间的相似度,同样也可以得到
余弦相似度
向量内积的结果是没有界限的,一种解决办法是除以长度之后再求内积,这就是应用十分广泛的余弦相似度
余弦相似度与向量的幅值无关,只与向量的方向相关,在文档相似度
皮尔逊相关系数(Pearson Correlation Coefficient)
需要注意一点的是,余弦相似度受到向量的平移影响,上式如果将
=
$\frac{\sum x_iy_i-\frac{\sum x_i\sum y_i}{n}}{\sqrt{\sum x_i^2-\frac{(\sum x_i)^2}{n}}\sqrt{\sum y_i^2-\frac{(\sum y_i)^2}{n}}}$
在推荐系统中,我们常用皮尔逊相关系数来衡量两个用户兴趣的相似度,它是判断两组数据与某一直线拟合程度的一种度量。它在用户对物品的评分数据差别大时

在统计学中,皮尔逊积矩相关系数
皮尔逊相关系数具有平移不变性和尺度不变性,计算出了两个向量

由于皮尔逊系数具有的良好性质,在各个领域都应用广泛,例如,在推荐系统根据为某一用户查找喜好相似的用户
例如,假设五个国家的国民生产总值分别是
1 、2、3、5、8( 单位10 亿美元) ,又假设这五个国家的贫困比例分别是11% 、12%、13%、15%、18%。
创建
x<-c(1,2,3,5,8)
y<-c(0.11,0.12,0.13,0.15,0.18)
按照维基的例子
所以
sum((x-mean(x))*(y-mean(y)))=0.308
用大白话来写就是
(1-3.8)*(0.11-0.138)=0.0784
(2-3.8)*(0.12-0.138)=0.0324
(3-3.8)*(0.13-0.138)=0.0064
(5-3.8)*(0.15-0.138)=0.0144
(8-3.8)*(0.18-0.138)=0.1764
0.0784+0.0324+0.0064+0.0144+0.1764=0.308
同理
sum((x-mean(x))^2)=30.8
sum((y-mean(y))^2)= 0.00308
用大白话来写
7.84+3.24+0.64+1.44+17.64=30.8
同理
sum((y-mean(y))^2)= 0.00308
然后再开平方根
30.8^0.5=5.549775
0.00308^0.5=0.05549775
用分子除以分母
0.308/(5.549775*0.05549775)=1
#皮尔逊相关度
def sim_pearson(prefs,p1,p2):
si={}
for item in prefs[p1]:
if item in prefs[p2]: si[item]=1
if len(si)==0: return 0
n=len(si)
#计算开始
sum1=sum([prefs[p1][it] for it in si])
sum2=sum([prefs[p2][it] for it in si])
sum1Sq=sum([pow(prefs[p1][it],2) for it in si])
sum2Sq=sum([pow(prefs[p2][it],2) for it in si])
pSum=sum([prefs[p1][it]*prefs[p2][it] for it in si])
num=pSum-(sum1*sum2/n)
den=sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n))
#计算结束
if den==0: return 0
r=num/den
return r
序列距离(String,TimeSeries)
DTW(Dynamic Time Warp)
汉明距离可以度量两个长度相同的字符串之间的相似度,如果要比较两个不同长度的字符串,不仅要进行替换,而且要进行插入与删除的运算,在这种场合下,通常使用更加复杂的编辑距离
时间序列是序列之间距离的另外一个例子。

#!/usr/bin/python2
# -*- coding:UTF-8 -*-
# code related at: http://blog.mckelv.in/articles/1453.html
import sys
distance = lambda a,b : 0 if a==b else 1
def dtw(sa,sb):
'''
>>>dtw(u"干啦今今今今今天天气气气气气好好好好啊啊啊", u"今天天气好好啊")
2
'''
MAX_COST = 1<<32
#初始化一个len(sb) 行(i),len(sa)列(j)的二维矩阵
len_sa = len(sa)
len_sb = len(sb)
# BUG:这样是错误的(浅拷贝): dtw_array = [[MAX_COST]*len(sa)]*len(sb)
dtw_array = [[MAX_COST for i in range(len_sa)] for j in range(len_sb)]
dtw_array[0][0] = distance(sa[0],sb[0])
for i in xrange(0, len_sb):
for j in xrange(0, len_sa):
if i+j==0:
continue
nb = []
if i > 0: nb.append(dtw_array[i-1][j])
if j > 0: nb.append(dtw_array[i][j-1])
if i > 0 and j > 0: nb.append(dtw_array[i-1][j-1])
min_route = min(nb)
cost = distance(sa[j],sb[i])
dtw_array[i][j] = cost + min_route
return dtw_array[len_sb-1][len_sa-1]
def main(argv):
s1 = u'干啦今今今今今天天气气气气气好好好好啊啊啊'
s2 = u'今天天气好好啊'
d = dtw(s1, s2)
print d
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
网络节点距离
分布距离
前面我们谈论的都是两个数值点之间的距离,实际上两个概率分布之间的距离是可以测量的。在统计学里面经常需要测量两组样本分布之间的距离,进而判断出它们是否出自同一个
先从信息熵说起,假设一篇文章的标题叫做“黑洞到底吃什么”,包含词语分别是
对假设一个发送者要将随机变量
这就是熵的概念。另外一个重要特点是,熵的大小与字符平均最短编码长度是一样的
