一、推荐系统简介

推荐系统主要基于对用户历史的行为数据分析处理,寻找得到用户可能感兴趣的内容,从而实现主动向用户推荐其可能感兴趣的内容;

从物品的长尾理论来看,推荐系统通过发掘用户的行为,找到用户的个性化需求,从而将长尾商品准确地推荐给需要它的用户,帮助用户发现那些他们感兴趣但很难发现的商品。

推荐系统使用的是基于邻域的算法,一类是基于用户的协同过滤算法,另一类是基于物品的协同过滤算法;

二、数据集准备

我们采用GroupLens提供的MovieLens数据集

These files contain 1,000,209 anonymous ratings of approximately 3,900 movies
made by 6,040 MovieLens users who joined MovieLens in 2000.

使用一下code加载评分文件ml-1m/ratings.dat

def get_ratings():
ratings = pd.read_csv('ml-1m/ratings.dat',
sep='::',
names=['UserID', 'MovieID', 'Rating', 'Timestamp'],
nrows=100000
) return ratings

我们可以查看前五行的数据情况

rating = get_ratings()
print(rating.head()) UserID MovieID Rating Timestamp
0 1 1193 5 978300760
1 1 661 3 978302109
2 1 914 3 978301968
3 1 3408 4 978300275
4 1 2355 5 978824291

了解一下用户感兴趣的电影数量

rating = get_ratings()
plt.hist(rating['UserID'], bins=100, edgecolor='black')
plt.show()

三、基于用户的协同过滤算法

基于用户的协同过滤算法是推荐系统中最古老的算法,该算法首先需要找到跟当前用户兴趣相似的用户,然后将找到的用户感兴趣却不在当前用户兴趣列表的物品推荐给当前用户;

基于用户的协同过滤算法主要分为两步

  1. 找到和当前用户兴趣相似的用户集合;

该算法基于用户对物品的历史的正反馈行为计算用户兴趣相似度;我们给定用户u、v,令N(u)表示用户u曾经有过正反馈的物品集合,N(v)表示用户v曾经有过正反馈的物品集合;我们可以通过余弦相似度来计算用户u和v的相似度:

w_{uv} = \frac{N(u) \cap N(v)}{\sqrt {N(u) \cup N(v)}}

例如用户U对a、b、c有过正反馈记录,用户V对a、c有过正反馈记录;

U  a b c
V a c

我们利用余弦相似度可以计算U和V的兴趣相似度

\[w_{UV}=\frac{|\{a,b,c\} \cap \{a,c\}|}{\sqrt {|\{a,b,c\}| |\{a,c\}|}} = \frac{2}{\sqrt{6}}
\]

我们使用如下的user_similarity来计算用户相似性

def user_similarity(ratings):
matrix = []
rating_groups = ratings.groupby('UserID')
for u_id, u_ratings in rating_groups:
row = []
matrix.append(row)
u_movieIds = u_ratings['MovieID'].values
for v_id, v_ratings in rating_groups:
v_movieIds = v_ratings['MovieID'].values
u_v_movieIds = np.intersect1d(u_movieIds, v_movieIds)
similarity = len(u_v_movieIds)/math.sqrt(len(u_movieIds) * len(v_movieIds))
row.append(similarity) result = pd.DataFrame(matrix, columns= rating_groups.groups.keys(), index=rating_groups.groups.keys())
return result rating = get_ratings()
similarity_matrix = user_similarity(rating)
print(similarity_matrix.head(10)) 1 2 3 ... 667 668 669
1 1.000000 0.084657 0.115406 ... 0.010504 0.068680 0.076194
2 0.084657 1.000000 0.147945 ... 0.087529 0.161416 0.048839
3 0.115406 0.147945 1.000000 ... 0.085666 0.070014 0.077674
4 0.119898 0.153704 0.152783 ... 0.083438 0.036370 0.000000
5 0.097618 0.125142 0.059708 ... 0.119562 0.142134 0.059131
6 0.163017 0.114939 0.099710 ... 0.063529 0.000000 0.032915
7 0.049341 0.284641 0.150899 ... 0.164817 0.179605 0.099627
8 0.116508 0.201633 0.083139 ... 0.090808 0.113092 0.023525
9 0.200125 0.162482 0.122407 ... 0.118842 0.178069 0.053877
10 0.240081 0.215441 0.216773 ... 0.126021 0.083229 0.096951 [10 rows x 669 columns]

在以上代码中直接遍历所有的用户进行计算相似性,很多时候由于物品的数量比较多或者每个用户的兴趣关注点比较少,这会导致大量用户并不存在所谓的并集;我们可以先将数据结构反转为产品用户,然后计算不同用户感兴趣的产品总数和相关用户之间感兴趣的产品交集,最后再进行余弦相似性计算;

import math
import numpy as np
import pandas as pd def change_user_ratings(rating):
grouped = rating.groupby('MovieID')
result = {}
for movieId,m_rating in grouped:
result[movieId] = m_rating['UserID'].values df = pd.DataFrame({
'MovieID': result.keys(),
'UserIDs': result.values()
}) return df.set_index(df.columns.values[0]) def cal_count(product_users):
user_counts = {}
rel_user_counts = {}
for movieId, row in product_users.iterrows():
userIds = row['UserIDs']
for uid in userIds:
if uid not in user_counts:
user_counts[uid] = 0
user_counts[uid] += 1
for vid in userIds:
if (uid, vid) not in rel_user_counts:
rel_user_counts[(uid, vid)] = 0
rel_user_counts[(uid, vid)] += 1 user_counts = pd.DataFrame({'UserID': user_counts.keys(), 'Movie_Count': user_counts.values()})
rel_user_counts = pd.DataFrame({'Rel_UserID':rel_user_counts.keys(), 'Movie_Count':rel_user_counts.values()})
return user_counts.set_index(user_counts.columns.values[0]), rel_user_counts.set_index(rel_user_counts.columns.values[0]) def cosin_similarity(user_counts, rel_user_counts):
result = []
for u, u_row in user_counts.iterrows():
row = []
result.append(row)
u_count = u_row['Movie_Count']
for v, v_row in user_counts.iterrows():
v_count = v_row['Movie_Count']
if rel_user_counts.index.isin([(u,v)]).any():
count = rel_user_counts.at[(u,v), 'Movie_Count']
row.append(count/math.sqrt(u_count * v_count))
else:
row.append(0) return pd.DataFrame(result, index=user_counts.index.values, columns=user_counts.index.values) def user_similarity(ratings):
rating_users = change_user_ratings(ratings)
user_counts, rel_user_counts = cal_count(rating_users)
s = cosin_similarity(user_counts, rel_user_counts)
return s ratings = get_ratings()
similarity_matrix = user_similarity(ratings)
print(similarity_matrix.head(10)) 1 2 3 ... 667 668 669
1 1.000000 0.084657 0.115406 ... 0.010504 0.068680 0.076194
2 0.084657 1.000000 0.147945 ... 0.087529 0.161416 0.048839
3 0.115406 0.147945 1.000000 ... 0.085666 0.070014 0.077674
4 0.119898 0.153704 0.152783 ... 0.083438 0.036370 0.000000
5 0.097618 0.125142 0.059708 ... 0.119562 0.142134 0.059131
6 0.163017 0.114939 0.099710 ... 0.063529 0.000000 0.032915
7 0.049341 0.284641 0.150899 ... 0.164817 0.179605 0.099627
8 0.116508 0.201633 0.083139 ... 0.090808 0.113092 0.023525
9 0.200125 0.162482 0.122407 ... 0.118842 0.178069 0.053877
10 0.240081 0.215441 0.216773 ... 0.126021 0.083229 0.096951 [10 rows x 669 columns]
  1. 找到这个用户集合感兴趣的且当前用户没有听说过的物品推推荐给他;

通过以上计算我们得到了用户相似性的矩阵,接下来我们需要找到跟目标用户兴趣最相似的K个用户,然后将只有这K个用户喜欢的物品推荐给目标用户;这里我们需要进一步度量目标用户对特定产品的感兴趣程度

在这个公式中,S(u,K)包含和用户u兴趣最接近的K个用户,N(i)是对物品i有过行为的用户集合,Wuv 是用户u和用户v的兴趣相似度,rvi 代表用户v对物品i的兴趣,因为使用的是单一行为的隐反馈数据,所以所有的rvi=1。

\[p(u,i) = \sum_{v \in s(u,K) \cap N(i)} w_{uv} r_{vi}
\]

我们使用以下的recommend方法实现这个推荐

def recommend(ratings,u, matrix, k):
result = pd.Series(dtype='float64');
grouped = dict(list(ratings.groupby('UserID')))
u_ratings = grouped[u][['MovieID','Rating']]
row = matrix.loc[u].sort_values(ascending=False)
for v in row.index:
if u != v:
similarity = row.loc[v]
v_ratings = grouped[v][['MovieID','Rating']]
diff = pd.concat([v_ratings, u_ratings, u_ratings]).drop_duplicates(subset=pd.Index(['MovieID']), keep=False)
for movieId, s_rating in diff.set_index('MovieID').iterrows():
like = similarity * (s_rating['Rating']/5)
s_movieId = str(movieId)
if movieId in result:
result[s_movieId] += like
else:
result[s_movieId] = like return result.sort_values(ascending=False).head(k)

我们计算推荐给用户A且其最感兴趣的前三件商品;从计算结果可以看到是商品c和e;

ratings = get_ratings()
similarity_matrix = user_similarity(ratings)
recommend_movies = recommend(ratings, 1, similarity_matrix, 10)
print(recommend_movies.head(10)) 2049 0.240081
3292 0.212965
1067 0.204131
2559 0.193922
3620 0.168068
963 0.168068
2179 0.165928
2211 0.165928
1817 0.165928
2227 0.165928
dtype: float64

注:由于rating.data的数据实际情况,每个用户以及每个电影都会有对应的评分,所以第二种算法并不具有什么性能优势,需要根据自己数据的实际情况进行选择;

elasticsearch算法之推荐系统的相似度算法(一)的更多相关文章

  1. elasticsearch算法之词项相似度算法(一)

    一.词项相似度 elasticsearch支持拼写纠错,其建议词的获取就需要进行词项相似度的计算:今天我们来通过不同的距离算法来学习一下词项相似度算法: 二.数据准备 计算词项相似度,就需要首先将词项 ...

  2. elasticsearch算法之词项相似度算法(二)

    六.莱文斯坦编辑距离 前边的几种距离计算方法都是针对相同长度的词项,莱文斯坦编辑距离可以计算两个长度不同的单词之间的距离:莱文斯坦编辑距离是通过添加.删除.或者将一个字符替换为另外一个字符所需的最小编 ...

  3. 百度面试题 字符串相似度 算法 similar_text 和页面相似度算法

    在百度的面试,简直就是花样求虐. 首先在面试官看简历的期间,除了一个自己定义字符串相似度,并且写出求相似度的算法. ...这个确实没听说过,php的similar_text函数也是闻所未闻的.之前看s ...

  4. Spark/Scala实现推荐系统中的相似度算法(欧几里得距离、皮尔逊相关系数、余弦相似度:附实现代码)

    在推荐系统中,协同过滤算法是应用较多的,具体又主要划分为基于用户和基于物品的协同过滤算法,核心点就是基于"一个人"或"一件物品",根据这个人或物品所具有的属性, ...

  5. 14、RALM: 实时 look-alike 算法在推荐系统中的应用

    转载:https://zhuanlan.zhihu.com/p/71951411 RALM: 实时 look-alike 算法在推荐系统中的应用 0. 导语 本论文题为<Real-time At ...

  6. 图像相似度算法的C#实现及测评

    近日逛博客的时候偶然发现了一个有关图片相似度的Python算法实现.想着很有意思便搬到C#上来了,给大家看看. 闲言碎语 才疏学浅,只把计算图像相似度的一个基本算法的基本实现方式给罗列了出来,以至于在 ...

  7. python 下的数据结构与算法---2:大O符号与常用算法和数据结构的复杂度速查表

    目录: 一:大O记法 二:各函数高阶比较 三:常用算法和数据结构的复杂度速查表 四:常见的logn是怎么来的 一:大O记法 算法复杂度记法有很多种,其中最常用的就是Big O notation(大O记 ...

  8. 文本相似度算法——空间向量模型的余弦算法和TF-IDF

    1.信息检索中的重要发明TF-IDF TF-IDF是一种统计方法,TF-IDF的主要思想是,如果某个词或短语在一篇文章中出现的频率TF高,并且在其他文章中很少出现,则认为此词或者短语具有很好的类别区分 ...

  9. 字符串相似度算法——Levenshtein Distance算法

    Levenshtein Distance 算法,又叫 Edit Distance 算法,是指两个字符串之间,由一个转成另一个所需的最少编辑操作次数.许可的编辑操作包括将一个字符替换成另一个字符,插入一 ...

随机推荐

  1. 【LeetCode】1151. Minimum Swaps to Group All 1's Together 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 滑动窗口 日期 题目地址:https://leetco ...

  2. 【LeetCode】515. Find Largest Value in Each Tree Row 解题报告(Python & C++ & Java)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 BFS DFS 日期 题目地址:https://le ...

  3. 【剑指Offer】矩阵覆盖 解题报告(Python)

    [剑指Offer]矩阵覆盖 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://www.nowcoder.com/ta/coding-interviews 题目描 ...

  4. 【LeetCode】60. Permutation Sequence 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  5. Android开发 ListView(垂直滚动列表项视图)的简单使用

    效果图: 使用方法: 1.在布局文件中加入ListView控件: <?xml version="1.0" encoding="utf-8"?> &l ...

  6. Hive on Spark和Spark sql on Hive,你能分的清楚么

    摘要:结构上Hive On Spark和SparkSQL都是一个翻译层,把一个SQL翻译成分布式可执行的Spark程序. 本文分享自华为云社区<Hive on Spark和Spark sql o ...

  7. CSS基础 列表相关的属性的使用

    1.无序列表:就是不需要排列顺序的情况,用无序列表 语法结构:<ul> <li></li> <li></li> </ul> 特点 ...

  8. C语言 Make命令教程

    make只是一个根据指定的Shell命令进行构建的工具 在linux和unix中,有一个强大的使用程序,叫make,可以用它来管理多模块程序的编译和链接,直至生成可执行文件 make使用程序读取一个说 ...

  9. JMeter跨线程,怎么定义全局变量,跨线程使用变量?

    JMeter跨线程时,怎么定义全局变量,跨线程使用此变量? 通过函数助手,获取到设置变量的语法脚本 2.通过Bean shell Sampler取样器,定义全局变量 3.定义好全局变量,可以调用,调用 ...

  10. 官方文档粗读 - Tutorial

    参考: https://www.jianshu.com/p/0d234e14b5d3 1.Connecting 我们通过 create_engine() 来链接数据库,假设我们我们采用SQLite. ...