特征向量的欧式距离与余弦距离——推荐算法


1.前言

近期热播的《长安十二时辰》中大案牍术推荐出的不良帅、网易云音乐的每日歌曲推荐,这些生活中看似神乎其技的方法,用一个数公式便可简单实现。

2.欧几里得空间

2.1 简介

大名鼎鼎的欧几里得在他大名鼎鼎的著作《几何原本》中:
image.png

通过几何(即欧氏几何,从小学到高中,我们学习的就是欧氏几何)来描述、研究这个世界:

image.png

在几何世界中,世界上的所有东西都可以用几何来表示,比如可以把世界上每个人表示为一串特征向量,这个特征向量记录了这个人的性格,外貌,经历,职业,年龄…等等数据,然后根据这些数据,只需一个公式便可找出与你相似的人。是不是很熟悉——大案牍术

image.png

假设AB是俩个人,a1,a2,b1,b2分别是这俩个人的年龄与性格,那么在直角坐标系可如此表示,θ的角度越小说明你们俩个人的相似度越高(至于这个公式怎么计算出来的,老弟,回去看课本吧)

那么当维度不在二维,扩展到三维,四维,一百维呢?这个公式仍然是有效的

中国有句古话,“有缘千里来相会,无缘对面手难牵”:
image.png

这句话有两种不一样的距离:

  • 千里、对面:直线距离,也叫欧氏距离,也就是刚才说的长度
  • 有缘、无缘:余弦距离,也就是刚才说的角度

2.2 欧式距离


比如,求a与b的欧氏距离:

image.png

image.png

我们手机信号会随着与基站距离的增大而衰减,这里的距离就是指的欧氏距离:
image.png

在多维空间中,要知道两个点的距离的远近,就可以用欧式距离。

2.3 余弦距离

“有缘”、“无缘”,翻译成大白话,就是关系是否紧密。描述关系紧密的就是余弦距离。
从几何上看,两个向量夹角几乎为0时,非常相似;
image.png
当然夹角为0的时候,两者关系最为紧密,此时余弦值为1。而相互垂直时,余弦值为0,相关性最差,或称相互独立

3.应用

正因为余弦距离解释了事物的相关性,所以有非常多的应用。比如在数据挖掘中,很多时候通过比较用户数据的余弦距离,以判断用户的相似性。
下面是某书评网站,用户对一些书籍进行了相应的评分:
image.png
那么第一个用户信息可以用向量image.png来表示。
第二个的用户信息可以用向量image.png来表示。
则它们的相似性就可以用余弦距离来表示:
image.png
带入数据,结果保留到小数点后两位:
image.png
以此类推,我们就可以做出如下表格,表明各个用户的相似性:
image.png
但是这有一个问题,比如第一个用户喜好假如是:
image.png

也就是说他对所有的书评分都为1。
而第二个用户的喜好是:
image.png
也就是说他对所有的书评分都为5。
按照我们的直觉,这两个人喜好是很不相同,但是:
image.png
余弦距离居然表明两者的喜好是相同的。

我们来改进一下:

  • 5分,表示很喜欢,实际值为2
  • 4分,表示喜欢,实际值为1
  • 3分,表示中性态度,实际值为0
  • 2分,表示讨厌,实际值为-1
  • 1分,表示很讨厌,实际值为-2
  • 不打分,默认实际值为0

因此,第一个用户喜好的实际值为:
image.png
而第二个用户喜好的实际值为:
image.png
结果:
image.png
-1表示两人的爱恨是相反的。


-1,也就是相反的爱恨不代表不相关,我们可以这么来看,比如我们知道第一个用户和第二个用户的余弦距离为-1,那么第一个用户喜欢的就不要推荐给第二个用户,第一个用户讨厌的可以推荐给第二个用户,所以实际两人是相关的,而且还非常相关。——网易云音乐推荐


有句话怎么说来着:
爱的相反词,不是恨,是冷漠。

4.代码

纸上得来终觉浅,下面我们简单实现一个特征向量的余弦,并思考一下特征向量该如何抓取:

url理解为上面的每一个人,url上的每一个字符都是这个人的特征向量中的一位数——万物皆几何

#coding=utf-8
'''
维度
'''
dim = 256

'''
将字符串转化为特征向量后,计算字符串之间的余弦相似度
'''

def turn_num(str):
    '''
    转化为特征向量
    :param str: str
    :return: str的特征向量
    '''
    str = list("".join([j for j in str]))
    for i in range(0, len(str)):
        str[i] = ord(str[i]) #ASCII
    for i in range(len(str), dim):#url不够dim位数补0特征向量
        str.append(0) 
    return str


def cos(vector1,vector2):
    '''
    余弦相似度计算
    :param vector1: url1
    :param vector2: url2
    :return: 相似度大小
    '''
    dot_product = 0.0 #点积
    normA = 0.0
    normB = 0.0
    for a,b in zip(vector1,vector2):
        dot_product += a*b
        normA += a**2
        normB += b**2
    if normA == 0.0 or normB==0.0:
        return None
    else:
        return dot_product / ((normA*normB)**0.5) #余弦距离

def compare(str,strOther):
    str = turn_num(str)
    strOther = turn_num(strOther)
    relate = cos(str, strOther)
    return relate

if __name__ == '__main__':
    str = 'http://www.baidu.com/detail.html?id=35047'
    strOther = 'http://www.baidu.com/detail.html?id=312312&aa=11'
    # str = '你好特普朗'
    # strOther = '你好特普朗翻翻'

    print(compare(str,strOther))

对于特征向量的抓取是比较麻烦的,会涉及到 特征工程:特征获取、特征处理、特征监控…
而上面的代码简单实现了特征向量的处理与使用,但是本质是不变的。

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值