前言
在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于协同过滤算法,这一实现个性化推荐的核心技术。我们将探究基于用户和基于物品的两种协同过滤方法,并分析它们的优缺点。同时,深入讨论相似度盘算方法,这是影响推荐效果的关键。通过两个详细案例——基于文章和基于用户的协同过滤推荐功能,我们将展示协同过滤算法在实际应用中的魅力。这些案例不仅帮助理解算法原理,也提供了实战参考。希望本文能引导你掌握协同过滤算法精髓,并能在实践中灵活运用,为构建精准、高效的推荐系统贡献力量。
一、协同过滤
协同过滤(Collaborative Filtering, CF) 是一种广泛应用于推荐系统中的算法,它通太过析用户的行为和偏好,发现用户之间的相似性(或物品之间的相似性),从而为用户推荐他们大概感兴趣的物品。常用来实现推荐模块的协同过滤算法重要分为两类:基于用户的协同过滤(User-Based Collaborative Filtering, UserCF) 和 基于物品的协同过滤(Item-Based Collaborative Filtering, ItemCF)。
1. 基于用户的协同过滤(UserCF)
根本思想:
基于用户的协同过滤算法通太过析用户对物品的喜欢来找到与用户兴趣相似的其他用户,然后将这些相似用户喜欢的、且目标用户尚未听说过的物品推荐给目标用户。这种方法以为,假如两个用户在过去的喜欢上有许多重叠,那么他们将来大概也会对雷同的物品感兴趣。
算法步骤:
- 收集用户行为数据: 通常包括用户评分、购买、浏览等行为数据。
- 盘算用户相似度: 利用相似度盘算方法(如余弦相似度、皮尔逊相关系数等)来盘算用户之间的相似度。
- 生成推荐列表: 根据相似用户的喜欢来预测目标用户对未评分物品的兴趣水平,并生成推荐列表。
优点:
- 可以或许捕获到用户的动态兴趣变化。
- 对于新用户来说,只要有足够的相似用户,也能产生不错的推荐效果。
缺点:
- 随着用户数目标增长,盘算用户相似度的开销会急剧上升。
- 对于用户兴趣分布不匀称的情况,大概无法找到足够多的相似用户。
2. 基于物品的协同过滤(ItemCF)
根本思想:
基于物品的协同过滤算法通太过析用户对差别物品的喜欢来找到与目标物品相似的其他物品,然后将这些相似物品推荐给喜欢目标物品的用户。这种方法以为,假如两个物品被许多雷同的用户喜欢,那么这两个物品之间就存在某种相似性,因此可以将一个物品推荐给喜欢另一个物品的用户。
算法步骤:
- 收集用户行为数据: 与用户CF雷同。
- 盘算物品相似度: 利用相似度盘算方法(如余弦相似度、杰卡德相似度等)来盘算物品之间的相似度。
- 生成推荐列表: 根据用户对已评分物品的喜欢和物品之间的相似度来预测用户对未评分物品的兴趣水平,并生成推荐列表。
优点:
- 可以或许处理大规模数据集,因为物品之间的相似度是静态的,可以离线盘算并存储。
- 可以或许发现物品之间的隐式关系,进步推荐的多样性。
缺点:
- 对于新用户来说,假如没有足够的行为数据,大概无法产生有效的推荐。
- 推荐的实时性较差,因为物品之间的相似度是预先盘算好的。
3. 相似度盘算方法
在实现协同过滤算法时,常用的相似度盘算方法包括:
- 余弦相似度: 衡量两个向量在方向上的相似水平,取值范围在[-1,1]之间。
- 皮尔逊相关系数: 在余弦相似度的基础上考虑了向量的大小(即评分的尺度),更适合处理具有差别评分尺度的用户数据。
- 杰卡德相似系数: 重要用于衡量两个聚集之间的相似度,实用于用户-物品交互数据非常稀疏的情况。
综上所述,协同过滤算法通过利用用户或物品之间的相似性来产生推荐,具有实现简单、效果显著等优点,是推荐系统中常用的算法之一。然而,它也存在一些局限性,如冷启动题目、稀疏性题目等,需要在实际应用中结合其他算法和技术来加以解决。
二、相似度盘算方法
1. 欧氏间隔
在协同过滤算法中,物品之间的相似度盘算是推荐系统的紧张组成部分,而欧几里得间隔(Euclidean Distance) 作为一种常用的间隔度量方式,也可以被转化为相似度指标来评估物品之间的相似水平。
欧几里得间隔,也称为欧式间隔,是在多维空间中两点之间的直线间隔。在二维空间中,它可以通过勾股定理来盘算;在多维空间中,则可以通过盘算各维度上差的平方和的平方根来得到。对于物品之间的相似度盘算,我们可以将每个物品视为多维空间中的一个点,其中每个维度代表物品的一个特性(如用户对物品的评分、物品的某些属性等)。
欧几里得间隔转化为相似度:
虽然欧几里得间隔自己表示的是两点之间的物理间隔,但在实际应用中,我们通常希望得到一个表示相似度的值,而不是间隔。因此,需要将欧几里得间隔转化为相似度。然而,需要留意的是,欧几里得间隔与相似度是成反比的,即间隔越大,相似度越小;间隔越小,相似度越大。
为了将欧几里得间隔转化为相似度,可以接纳以下几种方法:
- 间隔的倒数: 直接利用间隔的倒数作为相似度值,即1/d。但这种方法在间隔接近0时会导致相似度值趋于无穷大,因此大概需要进一步处理(如加1或设置上限)。
- 间隔的倒数加常数: 为了克制上述题目,可以在间隔的倒数上加一个常数(如1),即1/(d+1)。如许,纵然间隔很小,相似度值也不会过大。
- 归一化处理: 将盘算得到的相似度值进行归一化处理,使其落在某个特定的区间内(如[0,1]),以便与其他相似度盘算方法的结果进行比较。
- 利用其他相似度度量: 虽然欧几里得间隔自己不适合直接作为相似度度量,但可以通过其他方式(如余弦相似度、皮尔逊相关系数等)来盘算物品之间的相似度。
2. 皮尔逊相关系数
皮尔逊相关系数(Pearson Correlation Coefficient) 是统计学中用于度量两个变量X和Y之间线性相关水平的一种方法。在协同过滤算法中,特别是基于用户的协同过滤(UserCF)中,皮尔逊相关系数被广泛应用于盘算用户之间的相似度。
在基于用户的协同过滤中,我们通常利用用户对物品的评分数据来盘算用户之间的相似度。 设用户U1和用户U2分别对n个物品进行了评分,则可以通过盘算这两个用户评分向量的皮尔逊相关系数来评估他们之间的相似度。详细地,将用户对每个物品的评分视为一个变量,则两个用户的评分向量就可以看作是这些变量的两个观测值序列。通过盘算这两个序列的皮尔逊相关系数,我们就可以得到一个介于-1和1之间的数值,用于表示这两个用户之间的相似度。
3. 杰卡德相似系数
用户之间的相似度盘算方法中的杰卡德相似系数(Jaccard Similarity Coefficient) 是一种用于衡量两个聚集之间相似度的指标,它也可以应用于用户之间的相似度盘算,特别是在用户行为数据(如购买记载、浏览历史等)可以表示为聚集情势时。
应用场景:
在用户相似度盘算中,杰卡德相似系数实用于以了局景:
- 电商推荐: 在电商平台中,可以根据用户的购买记载盘算用户之间的杰卡德相似系数,从而找出具有相似购买行为的用户群体,并为他们推荐大概感兴趣的商品。
- 交际网络: 在交际网络中,可以根据用户的关注、点赞、评论等行为数据盘算用户之间的杰卡德相似系数,以发现潜在的朋侪关系或兴趣群体。
- 内容推荐: 在新闻、视频、音乐等内容推荐场景中,可以根据用户的历史浏览或消费记载盘算用户之间的杰卡德相似系数,从而为用户推荐与其兴趣相似的内容。
4. 余弦相似度
协同过滤中的余弦相似度是一种常用的用户或物品相似度盘算方法,它通过盘算两个向量在向量空间中夹角的余弦值来评估它们的相似度。
示例代码:
- # -*- coding: utf-8 -*-
- import numpy as np
- import pandas as pd
- userid =1008
- exportdata = []
- goodsidlist = []
-
- def load_data(file_path):
- global userid
- global goodsidlist
- '''导入用户商品数据
- input: file_path(string):用户商品数据存放的文件
- output: data(mat):用户商品矩阵
- '''
- filedata = pd.read_csv(file_path)
-
- # print(filedata.values[0][0])
- data1 = filedata.drop(['userid'],axis=1)
- data = pd.DataFrame(data1)
- goodsidlist = data.columns.values.tolist()
- return np.mat(data)
-
- def cos_sim(x, y):
- '''余弦相似性
- input: x(mat):以行向量的形式存储,可以是用户或者商品
- y(mat):以行向量的形式存储,可以是用户或者商品
- output: x和y之间的余弦相似度
- '''
- numerator = x * y.T # x和y之间的额内积
- denominator = np.sqrt(x * x.T) * np.sqrt(y * y.T)
- return (numerator / denominator)[0, 0]
-
-
- def similarity(data):
- '''计算矩阵中任意两行之间的相似度
- input: data(mat):任意矩阵
- output: w(mat):任意两行之间的相似度
- '''
- m = np.shape(data)[0] # 用户的数量
- # 初始化相似度矩阵
- w = np.mat(np.zeros((m, m)))
-
- for i in range(m):
- for j in range(i, m):
- if j != i:
- # 计算任意两行之间的相似度
- w[i, j] = cos_sim(data[i, ], data[j, ])
- w[j, i] = w[i, j]
- else:
- w[i, j] = 0
- return w
-
- def user_based_recommend(data, w, user):
- '''基于用户相似性为用户user推荐商品
- input: data(mat):用户商品矩阵
- w(mat):用户之间的相似度
- user(int):用户的编号
- output: predict(list):推荐列表
- '''
- m, n = np.shape(data)
- interaction = data[user, ] # 用户user与商品信息
-
- # print(interaction)
- # 1、找到用户user没有互动过的商品
- not_inter = []
- for i in range(n):
- if interaction[0, i] == 0: # 没有互动的商品
- not_inter.append(i)
-
- # 2、对没有互动过的商品进行预测
- predict = {}
-
- for x in not_inter:
- item = np.copy(data[:, x]) # 找到所有用户对商品x的互动信息
- for i in range(m): # 对每一个用户
- if item[i, 0] != 0: # 若该用户对商品x有过互动
- if x not in predict:
- predict[x] = w[user, i] * item[i, 0]
- else:
- predict[x] = predict[x] + w[user, i] * item[i, 0]
- # 3、按照预测的大小从大到小排序
- return sorted(predict.items(), key=lambda d:d[1], reverse=True)
-
- def top_k(predict, k):
- '''为用户推荐前k个商品
- input: predict(list):排好序的商品列表
- k(int):推荐的商品个数
- output: top_recom(list):top_k个商品
- '''
- top_recom = []
- len_result = len(predict)
- if k >= len_result:
- top_recom = predict
- else:
- for i in range(k):
- top_recom.append(predict[i])
- return top_recom
-
- if __name__ == "__main__":
- # 1、导入用户商品数据
- # print ("------------ 1. load data ------------")
- data = load_data("orders.csv")
- # 2、计算用户之间的相似性
- # print ("------------ 2. calculate similarity between users -------------")
- w = similarity(data)
- # 3、利用用户之间的相似性进行推荐
- # print ("------------ 3. predict ------------userid:::"+str(userid))
- predict = user_based_recommend(data, w, userid)
- # 4、进行Top-K推荐
- # print ("------------ 4. top_k recommendation ------------")
- top_recom = top_k(predict, 5)
- relist=[]
- for i in top_recom:
- key = i[0]
- relist.append(goodsidlist[key])
- print(relist)
复制代码 三、推荐模块案例
业务背景:
在一个大型的在线内容平台,用户可以阅读各种类型的文章,包括新闻、博客、教程等。随着平台上内容的不断增长,用户面临着信息过载的题目,很难快速找到自己感兴趣的内容。为了进步用户体验,增长用户参加度和满意度,平台决定开发一个基于协同过滤算法的推荐模块,帮助用户发现个性化的内容。
1.基于文章的协同过滤推荐功能
创建一个基于文章的协同过滤推荐功能的 Django 应用涉及到多个步骤,包括设计模型、收集用户行为数据、盘算相似度和生成推荐。以下是一个简化的示例,展示怎样利用 Django 实现协同过滤推荐功能。
步骤一:设计模型
Category(分类表)
字段名数据类型形貌nameVARCHAR(100)分类名称,唯一 Article(文章表)
字段名数据类型形貌titleVARCHAR(255)标题contentTEXT内容authorVARCHAR(100)作者cateidForeignKey(Category)分类,外键关联分类表tagsManyToManyField(Tag)标签,多对多关联标签表 Tag(标签表)
字段名数据类型形貌nameVARCHAR(100)标签名称,唯一 UserBrowseRecord(用户浏览记载表)
字段名数据类型形貌user_idForeignKey(User)用户ID,外键关联用户表article_idForeignKey(Article)文章ID,外键关联文章表tag_idForeignKey(Tag)标签ID,外键关联标签表countINTEGER浏览次数,默以为0 步骤二:收集用户行为数据
在这个示例中,假设用户已经浏览过多篇文章,用户浏览记载表UserBrowseRecord已有对应的浏览记载。
步骤三:盘算相似度并生成推荐
正常流程下,应该先构建一个方法用于盘算用户之间的相似度(利用余弦相似度、皮尔逊相关系数等盘算方法),并返回相似用户的分数;然后根据相似用户的评分来推荐文章。
但是也可通过设置定时任务,每天晚上跑一次,查询用户浏览记载表根据次数排序,取前5个标签,根据标签去获取商品表中浏览次数最高前10篇文章,放到缓存。用户在推荐页获取推荐文章时,直接从缓存中获取。
- class RecommendTest(APIView):
- def get(self, request):
- # 此函数中的内容可设置定时任务,定时更新对于不同用户的推荐信息
- # 获取所有用户信息
- users = User.objects.all()
- for user in users:
- # **对每个用户,获取其浏览记录,并将其推荐信息存储到redis中**
- uviews = UserBrowseRecord.objects.filter(user_id=user.id).order_by("-count").all()[:5]
- ids = [i.tag_id for i in uviews]
- recommend = Article.objects.filter(tags__in=ids).order_by("-id").all()[:10]
- recommend_data = ArticleSerializer(recommend,many=True).data
- r.set_str("usercommend"+str(user.id),json.dumps(recommend_data))
- return Response({"code":200,"mes":"推荐信息存储成功"})
-
- def post(self, request):
- #获取此userid缓存在redis中的推荐信息
- userid = request.data.get("userid")
- data = r.get_str("usercommend"+str(userid))
-
- return Response({"code":200,"mes":json.loads(data)})
复制代码 2.基于用户的协同过滤推荐功能
1.收集数据,浏览记载表
2.查询与当前用户相似度最高的10个用户
3.查询那10个用户近期游览记载,取20条。与用户最近浏览取差集
- def recommend_articles(request):
- # 获取当前用户的所有购买的商品标签
- user_ratings = list(UserBrowseRecord.objects.filter(user_id=1).values('article_id'))
- print("user_ratings ==> ",user_ratings)
- strs = [i['article_id'] for i in user_ratings]
- print("article_strs ==> ",strs)
- # 这文章被哪些人看过
- userlist = UserBrowseRecord.objects.filter(article_id__in=strs).values("user_id", 'count')
- print("userlist ==> ",userlist)
- print("len(userlist) ==> ",len(userlist))
- dict = {}
- for i in userlist:
- if i['user_id'] in dict:
- dict[i['user_id']] += i['count']
- else:
- dict[i['user_id']] = i['count']
- print("user_list ==> ",dict)
- # 相似度最高的用户列表
- similar_users = sorted(dict.items(), key=lambda x: x[1], reverse=True)[:10]
- print("similar_users ==> ",similar_users)
- # 获取这些用户看过的文章/标签?
- user_articles = [i['article_id'] for i in UserBrowseRecord.objects.filter(user_id__in=[i[0] for i in similar_users]).values('article_id')]
- print("user_articles ==> ",user_articles)
- # 文章 与 用户看过取差集
- recommend_articles = list(set(user_articles) - set(strs))
- print("recommend_articles ==> ",recommend_articles)
- # 根据tagid 获取此标签对应的阅读量最多的文章取前10个
- # recommend_articles_list = Article.objects.filter(id__in=recommend_articles).order_by("-id")[:10]
- return JsonResponse({"code": 200, 'recommend_articles_list': recommend_articles})
复制代码 
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |