常用的相似性度量算法(原理,实现,优缺点,适用场景) 更新ing

对相似性算法的了解起源于最近在做使用协同过滤原理的推荐系统中,基于邻域的推荐算法(User-Based CF和 和 Item-Based CF)需要估算不同样本之间的相似性度量(Similarity Measurement),这也是机器学习中在做分类的时候的一个常见场景。

相似度通常采用的方法就是计算样本间的“距离”(Distance)。采用什么样的方法计算距离是很讲究,甚至关系到分类的正确与否。

本文的目的在于对当下常见的相似度度量方法的原理,实现,优缺点,改进版本,适用场景等几个方面做一个总结

一、欧氏距离(EuclideanDistance)

欧氏距离欧几里得距离的简称,是最易于理解的一种距离计算方法,其实就是空间中两点间的距离公式。

  1. 二维平面上两点a(x1,y1)与b(x2,y2)间的欧氏距离(拓展到n维同理)


  1. 两个n维向量a(x11,x12,…,x1n)与 b(x21,x22,…,x2n)间的欧氏距离


  2. 向量运算的形式:


  3. 就其意义而言,欧氏距离越小,两个用户相似度就越大,欧氏距离越大,两个用户相似度就越小。而在日常使用中,一般习惯于将相似度与1类比,对越相似的人给出越大的值,相似度在数值上反映为0<=sim_distance(x,y)<=1,越接近1,相似度越高。所以我们需要进行归一化处理,可以通过将其函数值加1(避免除以0),并取其倒数的方法来构造欧几里得相似度函数:

  4. 用 python实现计算欧几里得距离,并构造相似度函数:

# @Author  : XZP
# @Email   : pcxzp@live.com
# @File    : EuclideanDistanceSimilarity.py

from math import sqrt

# 找到二者相同评分项
def get_same_Item(prefs, person1, person2):
    si = {}
    for item in prefs[person1]:
        if item in prefs[person2]:
            si[item] = 1
    return si

# 欧几里得相似度算法
def sim_euclid(prefs, p1, p2):
    si = get_same_Item(prefs, p1, p2)
    if len(si) == 0:
        return 0
    sum_of_squares = sum([pow(prefs[p1][item] - prefs[p2][item], 2) for item in si])
    return 1 / (1 + sqrt(sum_of_squares))

if __name__ == '__main__':
    critics = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
                             'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
                             'The Night Listener': 3.0},
               'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
                                'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
                                'You, Me and Dupree': 3.5}}

    print(sim_euclid(critics, 'Lisa Rose', 'Gene Seymour')) # 0.29429805508554946
  1. 缺点:当数据集出现异常值(即数据不是很规范)的时候,欧几里德距离表现不"稳定",另除了异常值外,当这种情况:例如A、B明明都喜欢这个电影,品味相似,但是B对电影的评分向来比较苛刻(评分都不太高),所以导致这时候用欧氏距离得出二者不相似的结论,这显然不是我们所期望的结果。

二、标准化欧氏距离

三、曼哈顿距离

四、切比雪夫距离

五、 夹角余弦距离

如果高中正常毕业, 参加过高考, 那么肯定会这么一个公式

cos<a, b> = a • b / |a|•|b|

假设

a = (3, 1, 0),
b =  (2, -1, 2)

分子是a,b两个向量的内积, (3, 1, 0) • (2, -1, 2) = 3•2 + 1•(-1) + 0•2 = 5
分母是两个向量模(模指的是向量的长度)的乘积.

总之这个cos的计算不要太简单

余弦距离(余弦相似度), 计算的是两个向量在空间中的夹角大小, 值域为[-1, 1]:
1代表夹角为, 完全重叠/完全相似;
-1代表夹角为180°, 完全相反方向/毫不相似.

余弦相似度的问题是: 其计算严格要求"两个向量必须所有维度上都有数值", 比如:

v1 = (1, 2, 4), 
v2 = (3, -1, null), 

那么这两个向量由于v2中第三个维度有null, 无法进行计算.

然而, 实际我们做数据挖掘的过程中, 向量在某个维度的值常常是缺失的, 比如

v2=(3, -1, null)

v2数据采集或者保存中缺少一个维度的信息, 只有两个维度.

那么, 我们一个很朴素的想法就是, 我们在这个地方填充一个值, 不就满足了"两个向量必须所有维度上都有数值"的严格要求了吗?

在填充值的时候, 一般我们用这个向量已有数据的平均值, 所以v2填充后变成

v2=(3, -1, 2), 

接下来我们就可以计算cos<v1, v2>了.(由此引出皮尔逊距离)

七、皮尔逊相关系数

皮尔逊相关系数(Pearson Correlation Coefficient)是余弦相似度在维度值缺失情况下的一种改进

  1. 首先我们来看皮尔森相似度的公式:
    假设有两个变量X、Y,那么两变量间的皮尔逊相关系数可通过以下公式计算:
    公式一:



    公式二:



    公式三:

    公式四:

以上列出的四个公式等价,其中E是数学期望,cov表示协方差,N表示变量取值的个数。

  1. 再来看皮尔逊相关系数的思路:皮尔逊是比欧几里德距离更加复杂的可以判断人们兴趣相似度的一种方法。该相关系数通过将两组数据与某一直线拟合的思想来求值,该值实际上就为该直线的斜率。其斜率的区间在[-1,1]之间,其绝对值的大小反映了两者相似度大小,斜率越大,相似度越大,当相似度为1时,该直线为一条对角线。
    也被称为“最佳拟合线”
  1. 再从余弦相似度的层面来理解皮尔逊相关系数,我把这些null的维度都填上0, 然后让所有其他维度减去这个向量各维度的平均值, 这样的操作叫作中心化。中心化之后所有维度的平均值就是0了(妙哇!), 也满足进行余弦计算的要求. 然后再进行我们的余弦计算得到结果. 这样先中心化再余弦计得到的相关系数叫作皮尔逊相关系数.由此再看计算皮尔逊相关系数的公式就明了了。

  2. 用 python实现计算皮尔森相似度:

# @Author  : XZP
# @Email   : pcxzp@live.com
# @File    : PersonSimilarity.py

from math import sqrt  
  
def sim_pearson(prefs, p1, p2):
    # Get the list of mutually rated items
    si = get_same_Item(prefs, p1, p2)
    n = len(si)

    # if they are no ratings in common, return 0
    if n == 0:
        return 0

    # Sums of all the preferences
    sum_x = sum([prefs[p1][it] for it in si])
    sum_y = sum([prefs[p2][it] for it in si])

    sum_x2 = sum([pow(prefs[p1][it], 2) for it in si])
    sum_y2 = sum([pow(prefs[p2][it], 2) for it in si])

    sum_xy = sum([prefs[p1][it] * prefs[p2][it] for it in si])

    # 计算系数
    num = sum_xy - (sum_x * sum_y / n)
    den = sqrt((sum_x2 - pow(sum_x, 2) / n) * (sum_y2 - pow(sum_y, 2) / n))
    if den == 0:
        return 0

    r = num / den

    return r

总结: 皮尔逊系数就是cos计算之前两个向量都先进行中心化(centered),余弦计算和皮尔逊相关系数计算就是一个东西两个名字啊

  1. 优点:
  • 它在数据不是很规范的时候,会倾向于给出更好的结果。
  • 修正了“夸大分值”的情况:二者有相对近似的偏好,但某人一般倾向于给出更高的分值,而二者的分值之差又始终保持一致,则他们依然可能会存在很好的相关性(单纯的用欧几里得距离,相似度会偏低,得出不相关的结论,这显然不是我们所期望的。)

八、汉明距离

pass

九、总结

其实你会发现,选择不同的相似性度量方法,对结果的影响是微乎其微的。 ——《集体智慧编程》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容