基于用户的协同过滤来构建推荐系统

2020 年 9 月 22 日 DataFunTalk



文章作者:哥不是小萝莉,来源:

https://www.cnblogs.com/smartloli/


导读: 协同过滤技术在推荐系统中应用的比较广泛,它是一个快速发展的研究领域。 它比较常用的两种方法是基于内存 (  Memory-Based )  和基于模型 (  Model-Based )
  • 基于内存:主要通过计算近似度来进行推荐,比如基于用户 ( Used-Based ) 和基于物品 ( Item-Based ) 的协同过滤,这两个模式中都会首先构建用户交互矩阵,然后矩阵的行向量和列向量可以用来表示用户和物品,然后计算用户和物品的相似度来进行推荐;

  • 基于模型:主要是对交互矩阵进行填充,预测用户购买某个物品的可能性。

为了解决这些问题,可以通过建立协同过滤模型,利用购买数据向客户推荐产品。下面,我们通过基于用户的协同过滤(基于内存),通过实战来一步步实现其中的细节。基于用户的系统过滤体现在具有相似特征的人拥有相似的喜好。比如,用户A向用户B推荐了物品C,而B购买过很多类似C的物品,并且评价也高。那么,在未来,用户B也会有很大的可能会去购买物品C,并且用户B会基于相似度度量来推荐物品C。

01

基于用户与用户的协同过滤

这种方式识别与查询用户相似的用户,并估计期望的评分为这些相似用户评分的加权平均值。实战所使用的Python语言,这里需要依赖的库如下:

  • pandas

  • numpy

  • sklearn

Python环境:

  • 版本3.7.6

  • Anaconda3

02

评分函数

这里给非个性化协同过滤(不包含活跃用户的喜欢、不喜欢、以及历史评分),返回一个以用户U和物品I作为输入参数的分数。该函数输出一个分数,用于量化用户U喜欢 / 偏爱物品I的程度。这通常是通过对与用户相似的人的评分来完成的。涉及的公式如下:

这里其中s为预测得分,u为用户,i为物品,r为用户给出的评分,w为权重。在这种情况下,我们的分数等于每个用户对该项目的评价减去该用户的平均评价再乘以某个权重的总和,这个权重表示该用户与其他用户有多少相似之处,或者对其他用户的预测有多少贡献。这是用户u和v之间的权重,分数在0到1之间,其中0是最低的,1是最高的。理论上看起来非常完美,那为啥需要从每个用户的评分中减去平均评分,为啥要使用加权平均而不是简单平均?这是因为我们所处理的用户类型,首先,人们通常在不同的尺度上打分,用户A可能是一个积极乐观的用户,会给用户A自己喜欢的电影平均高分(例如4分、或者5分)。而用户B是一个不乐观或者对评分标准比较高的用户,他可能对最喜欢的电影评分为2分到5分之间。用户B的2分对应到用户A的4分。改进之处是可以通过规范化用户评分来提高算法效率。一种方法是计算s(u,i)的分数,它是用户对每件物品的平均评价加上一些偏差。通过使用余弦相似度来计算上述公式中给出的权重,同时,按照上述方式对数据进行归一化,在pandas中进行一些数据分析。

1. 导入Python依赖包

import pandas as pdimport numpy as npfrom sklearn.metrics.pairwise import cosine_similarityfrom sklearn.metrics import pairwise_distances

2. 加载数据源

加载数据示例代码如下所示:

movies = pd.read_csv("data/movies.csv")Ratings = pd.read_csv("data/ratings.csv")Tags = pd.read_csv("data/tags.csv")

结果预览如下:

print(movies.head())print(Ratings.head())print(Tags.head())

构建数据:

Mean = Ratings.groupby(by="userId", as_index=False)['rating'].mean()Rating_avg = pd.merge(Ratings, Mean, on='userId')Rating_avg['adg_rating'] = Rating_avg['rating_x'] - Rating_avg['rating_y']print(Rating_avg.head())

结果如下:

03

余弦相似度

对于上面的公式,我们需要找到有相似想法的用户。找到一个喜欢和不喜欢的用户听起来很有意思,但是我们如何找到相似性呢?那么这里我们就需要用到余弦相似度,看看用户有多相似。它通常是根据用户过去的评分来计算的。

这里使用到Python的的sklearn的cosine_similarity函数来计算相似性,并做一些数据预处理和数据清洗。实例代码如下:

check = pd.pivot_table(Rating_avg,values='rating_x',index='userId',columns='movieId')print(check.head())final = pd.pivot_table(Rating_avg,values='adg_rating',index='userId',columns='movieId')print(final.head())

结果如下:

上图中包含了很多NaN的值,这是因为每个用户都没有看过所有的电影,所以这种类型的矩阵被称为稀疏矩阵。类似矩阵分解的方法被用来处理这种稀疏性,接下来,我们来对这些NaN值做相关替换。

这里通常有两种方式:

  • 使用行上的用户平均值;

  • 用户在列上的电影平均值

代码如下:

# Replacing NaN by Movie Averagefinal_movie = final.fillna(final.mean(axis=0))print(final_movie.head())
# Replacing NaN by user Averagefinal_user = final.apply(lambda row: row.fillna(row.mean()), axis=1)print(final_user.head())

结果如下:

接着,我们开始计算用户之间的相似性,代码如下:

# user similarity on replacing NAN by item(movie) avgcosine = cosine_similarity(final_movie)np.fill_diagonal(cosine, 0)similarity_with_movie = pd.DataFrame(cosine, index=final_movie.index)similarity_with_movie.columns = final_user.index# print(similarity_with_movie.head())
# user similarity on replacing NAN by user avgb = cosine_similarity(final_user)np.fill_diagonal(b, 0 )similarity_with_user = pd.DataFrame(b,index=final_user.index)similarity_with_user.columns=final_user.index# print(similarity_with_user.head())

结果如下:

然后,我们来检验一下我们的相似度是否有效,代码如下:

def get_user_similar_movies( user1, user2 ):    common_movies = Rating_avg[Rating_avg.userId == user1].merge(    Rating_avg[Rating_avg.userId == user2],    on = "movieId",    how = "inner" )    return common_movies.merge( movies, on = 'movieId' )
a = get_user_similar_movies(370,86309)a = a.loc[ : , ['rating_x_x','rating_x_y','title']]print(a.head())

结果如下:

从上图中,我们可以看出产生的相似度几乎是相同的,符合真实性。

04

相邻用户

刚刚计算了所有用户的相似度,但是在大数据领域,推荐系统与大数据相结合是至关重要的。以电影推荐为例子,构建一个矩阵(862 * 862),这个与实际的用户数据(百万、千万或者更多)相比,这是一个很小的矩阵。因此在计算任何物品的分数时,如果总是查看所有其他用户将不是一个好的解决方案或者方法。因此,采用相邻用户的思路,对于特定用户,只取K个类似用户的集合。

下面,我们对K取值30,所有的用户都有30个相邻用户,代码如下:

def find_n_neighbours(df,n):    order = np.argsort(df.values, axis=1)[:, :n]    df = df.apply(lambda x: pd.Series(x.sort_values(ascending=False)           .iloc[:n].index,          index=['top{}'.format(i) for i in range(1, n+1)]), axis=1)    return df
# top 30 neighbours for each usersim_user_30_u = find_n_neighbours(similarity_with_user,30)print(sim_user_30_u.head())
sim_user_30_m = find_n_neighbours(similarity_with_movie,30)print(sim_user_30_m.head())

结果如下:

05

计算最后得分

实现代码如下所示:

def User_item_score(user,item):    a = sim_user_30_m[sim_user_30_m.index==user].values    b = a.squeeze().tolist()    c = final_movie.loc[:,item]    d = c[c.index.isin(b)]    f = d[d.notnull()]    avg_user = Mean.loc[Mean['userId'] == user,'rating'].values[0]    index = f.index.values.squeeze().tolist()    corr = similarity_with_movie.loc[user,index]    fin = pd.concat([f, corr], axis=1)    fin.columns = ['adg_score','correlation']    fin['score']=fin.apply(lambda x:x['adg_score'] * x['correlation'],axis=1)    nume = fin['score'].sum()    deno = fin['correlation'].sum()    final_score = avg_user + (nume/deno)    return final_score
score = User_item_score(320,7371)print("score (u,i) is",score)

结果如下:

这里我们算出来的预测分数是4.25,因此可以认为用户(370),可能喜欢ID(7371)的电影。接下来,我们给用户(370)做电影推荐,实现代码如下:

Rating_avg = Rating_avg.astype({"movieId": str})Movie_user = Rating_avg.groupby(by = 'userId')['movieId'].apply(lambda x:','.join(x))
def User_item_score1(user): Movie_seen_by_user = check.columns[check[check.index==user].notna().any()].tolist() a = sim_user_30_m[sim_user_30_m.index==user].values b = a.squeeze().tolist() d = Movie_user[Movie_user.index.isin(b)] l = ','.join(d.values) Movie_seen_by_similar_users = l.split(',') Movies_under_consideration = list(set(Movie_seen_by_similar_users)-set(list(map(str, Movie_seen_by_user)))) Movies_under_consideration = list(map(int, Movies_under_consideration)) score = [] for item in Movies_under_consideration: c = final_movie.loc[:,item] d = c[c.index.isin(b)] f = d[d.notnull()] avg_user = Mean.loc[Mean['userId'] == user,'rating'].values[0] index = f.index.values.squeeze().tolist() corr = similarity_with_movie.loc[user,index] fin = pd.concat([f, corr], axis=1) fin.columns = ['adg_score','correlation'] fin['score']=fin.apply(lambda x:x['adg_score'] * x['correlation'],axis=1) nume = fin['score'].sum() deno = fin['correlation'].sum() final_score = avg_user + (nume/deno) score.append(final_score) data = pd.DataFrame({'movieId':Movies_under_consideration,'score':score}) top_5_recommendation = data.sort_values(by='score',ascending=False).head(5) Movie_Name = top_5_recommendation.merge(movies, how='inner', on='movieId') Movie_Names = Movie_Name.title.values.tolist() return Movie_Names
user = int(input("Enter the user id to whom you want to recommend : "))predicted_movies = User_item_score1(user)print(" ")print("The Recommendations for User Id : 370")print(" ")for i in predicted_movies: print(i)

结果如下:

06

总结

基于用户的协同过滤,流程简述如下:

  • 采集数据 & 存储数据

  • 加载数据

  • 数据建模(数据预处理 & 数据清洗)

  • 计算相似性(余弦相似度、相邻计算)

  • 得分预测(预测和最终得分计算)

  • 物品推荐

今天的分享就到这里,谢谢大家。

在文末分享、点赞、在看,给个三连击呗~~


作者介绍:

哥不是小萝莉,知名博主,著有《 Kafka 并不难学 》和《 Hadoop 大数据挖掘从入门到进阶实战 》。

邮箱:smartloli.org@gmail.com

会员推荐:

DataFun会员计划重磅发布!多重权益加持,为你筑就数据科学家之路!扫码了解更多:

文章推荐:

如何构建一个生产环境的推荐系统

关于我们:

DataFunTalk 专注于大数据、人工智能技术应用的分享与交流。发起于2017年,在北京、上海、深圳、杭州等城市举办超过100场线下沙龙、论坛及峰会,已邀请近500位专家和学者参与分享。其公众号 DataFunTalk 累计生产原创文章300+,百万+阅读,7万+精准粉丝。

🧐分享、点赞、在看,给个三连击呗!👇 

登录查看更多
0

相关内容

协同过滤(英语:Collaborative Filtering),简单来说是利用某兴趣相投、拥有共同经验之群体的喜好来推荐用户感兴趣的信息,个人透过合作的机制给予信息相当程度的回应(如评分)并记录下来以达到过滤的目的进而帮助别人筛选信息,回应不一定局限于特别感兴趣的,特别不感兴趣信息的纪录也相当重要。协同过滤又可分为评比(rating)或者群体过滤(social filtering)。其后成为电子商务当中很重要的一环,即根据某顾客以往的购买行为以及从具有相似购买行为的顾客群的购买行为去推荐这个顾客其“可能喜欢的品项”,也就是借由社群的喜好提供个人化的信息、商品等的推荐服务。除了推荐之外,近年来也发展出数学运算让系统自动计算喜好的强弱进而去芜存菁使得过滤的内容更有依据,也许不是百分之百完全准确,但由于加入了强弱的评比让这个概念的应用更为广泛,除了电子商务之外尚有信息检索领域、网络个人影音柜、个人书架等的应用等。
应用知识图谱的推荐方法与系统
专知会员服务
115+阅读 · 2020年11月23日
【KDD2020】 解决基于图神经网络的会话推荐中的信息损失
专知会员服务
31+阅读 · 2020年10月29日
【CIKM2020】学习个性化网络搜索会话
专知会员服务
14+阅读 · 2020年9月20日
专知会员服务
22+阅读 · 2020年9月8日
基于旅游知识图谱的可解释景点推荐
专知会员服务
90+阅读 · 2020年9月4日
基于知识图谱的推荐系统研究综述
专知会员服务
327+阅读 · 2020年8月10日
【SIGIR 2020】 基于协同注意力机制的知识增强推荐模型
专知会员服务
89+阅读 · 2020年7月23日
专知会员服务
87+阅读 · 2020年1月20日
推荐系统中的矩阵分解技术
AINLP
9+阅读 · 2018年12月24日
推荐系统概述
Python开发者
11+阅读 · 2018年9月27日
【推荐系统】详解基于内容的推荐算法
产业智能官
23+阅读 · 2018年1月11日
推荐系统机器学习算法概览
论智
7+阅读 · 2017年12月14日
详解个性化推荐五大最常用算法
量子位
4+阅读 · 2017年7月8日
Arxiv
9+阅读 · 2018年3月23日
Arxiv
5+阅读 · 2017年11月13日
VIP会员
相关VIP内容
应用知识图谱的推荐方法与系统
专知会员服务
115+阅读 · 2020年11月23日
【KDD2020】 解决基于图神经网络的会话推荐中的信息损失
专知会员服务
31+阅读 · 2020年10月29日
【CIKM2020】学习个性化网络搜索会话
专知会员服务
14+阅读 · 2020年9月20日
专知会员服务
22+阅读 · 2020年9月8日
基于旅游知识图谱的可解释景点推荐
专知会员服务
90+阅读 · 2020年9月4日
基于知识图谱的推荐系统研究综述
专知会员服务
327+阅读 · 2020年8月10日
【SIGIR 2020】 基于协同注意力机制的知识增强推荐模型
专知会员服务
89+阅读 · 2020年7月23日
专知会员服务
87+阅读 · 2020年1月20日
相关资讯
推荐系统中的矩阵分解技术
AINLP
9+阅读 · 2018年12月24日
推荐系统概述
Python开发者
11+阅读 · 2018年9月27日
【推荐系统】详解基于内容的推荐算法
产业智能官
23+阅读 · 2018年1月11日
推荐系统机器学习算法概览
论智
7+阅读 · 2017年12月14日
详解个性化推荐五大最常用算法
量子位
4+阅读 · 2017年7月8日
Top
微信扫码咨询专知VIP会员