余弦相似度算法

余弦相似度

余弦相似度 通过测量两个向量的夹角的余弦值来度量它们之间的相似性。0度角的余弦值是1,而其他任何角度的余弦值都不大于1;并且其最小值是-1。从而两个向量之间的角度的余弦值确定两个向量是否大致指向相同的方向。两个向量有相同的指向时,余弦相似度的值为1;两个向量夹角为90°时,余弦相似度的值为0;两个向量指向完全相反的方向时,余弦相似度的值为-1。这结果是与向量的长度无关的,仅与向量的指向方向相关。余弦相似度通常用于正空间,因此给出的值为0到1之间。

注意这上下界对任何维度的向量空间中都适用,而且余弦相似度最常用于高维正空间。例如在信息检索中,每个词被赋予不同的维度,而一个文档由一个向量表示,其各個维度上的值对应于该词在文档中出现的频率。余弦相似度因此可以给出两篇文档在其主题方面的相似度。

另外,它通常用于文本挖掘中的文件比较。此外,在数据挖掘领域中,会用到它来度量集群内部的凝聚力。

公式如下:

$$ \cos(x,y) = \frac{x \cdot y}{||x|| \cdot ||y||} $$

其中: “⋅”表示数量积. “||x||”表示向量x的模, 计算公式是:

$$ \sqrt{\sum_{i=1}^{n}x_{i}^{2}} $$

修正的余弦相似度

修正的余弦相似度可以说就是对余弦相似度进行归一化处理的算法. 公式如下:

$$ s(i, j) = \frac
{\sum_{u \in U}(R_{u,i} - R)(R_{u,j} - R)}
{
\sqrt{\sum_{u \in U}(R_{u,i} - R_{u})^{2}}
\sqrt{\sum_{u \in U}(R_{u,j} - R_{u})^{2}}
} $$

注意: 如果数据时稀疏的, 最好不要使用皮尔逊相关度和欧氏距离, 而使用余弦相似度.

代码如下:

import pandas as pd
import numpy as np
def get_users_intersection(book1, book2, data):
"""返回评价果"""
book1_users = data[data['book'] == book1]['userId'].values
book2_users = data[data['book'] == book2]['userId'].values
return np.intersect1d(book1_users, book2_users, assume_unique=True)
def get_user_mean(user, data):
"""返回均值"""
return data[data['userId'] == user]['rating'].mean()
def get_numerator(book1, book2, data):
"""返回分子"""
users = get_users_intersection(book1, book2, data)
if users:
result = 0
for u in users:
u_mean = get_user_mean(u, data)
books_ratings = data.loc[
data['userId'] == u][
data['book'].isin([book1, book2])]['rating']
result += np.cumprod(books_ratings.values - u_mean)[-1]
return result
return 0
def get_denominator(book1, book2, data):
"""返回分母"""
users = get_users_intersection(book1, book2, data)
if users:
result = 1
for u in users:
u_mean = get_user_mean(u, data)
books_ratings = data.loc[
data['userId'] == u][
data['book'].isin([book1, book2])]['rating']
books_ratings -= u_mean
books_ratings = books_ratings.pow(2) ** 0.5
result *= np.cumprod(books_ratings.values)[-1]
return result
return 0
def get_cos_rating(book1, book2, data):
denominator = get_denominator(book1, book2, data)
if denominator:
return get_numerator(book1, book2, data) / denominator
return -1
def get_data(path):
"""返回数据"""
data = pd.read_csv(path, sep=';', header=None)
data.columns = ['userId', 'book', 'rating']
return data
if __name__ == '__main__':
path = '../chapter-2/BX-Dump/BX-Book-Ratings.csv'
data = get_data(path)
data = data[data['rating'] > 0]
books = data.drop_duplicates('book')['book']
book1, book2 = books.sample(n=2).values
print (get_cos_rating(book1, book2, data))

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器