协同过滤方法, 基本思想是根据用户之前的喜好以及其他兴趣相近的用户的选择来给用户推荐物品(基于对用户历史行为数据的挖掘发现用户的喜好偏向, 并预测用户可能喜好的产品进行推荐),一般是仅仅基于用户的行为数据(评价、购买、下载等),而不依赖于项的任何附加信息(物品自身特征)或者用户的任何附加信息(年龄, 性别等)。
目前应用比较广泛的协同过滤算法是基于邻域的方法, 而这种方法主要有下面两种算法:
基于用户的协同过滤算法(UserCF): 给用户推荐和他兴趣相似的其他用户喜欢的产品基于物品的协同过滤算法(ItemCF): 给用户推荐和他之前喜欢的物品相似的物品两个用户 u 和 v 交互商品交集的数量占这两个用户交互商品并集的数量的比例,称为两个集合的杰卡德相似系数,用符号 sim 表示,其中 N(u),N(v)分别表示用户 u 和用户 v 交互商品的集合。 由于杰卡德相似系数一般无法反映具体用户的评分喜好信息, 所以常用来评估用户是否会对某商品进行打分, 而不是预估用户会对某商品打多少分。
余弦相似度衡量了两个向量的夹角,夹角越小越相似。首先从集合的角度描述余弦相似度,相比于Jaccard公式来说就是分母有差异,不是两个用户交互商品的并集的数量,而是两个用户分别交互的商品数量的乘积,公式如下: 从向量的角度进行描述,令矩阵 A 为用户-商品交互矩阵(因为是TopN推荐并不需要用户对物品的评分,只需要知道用户对商品是否有交互就行),即矩阵的每一行表示一个用户对所有商品的交互情况,有交互的商品值为1没有交互的商品值为0,矩阵的列表示所有商品。若用户和商品数量分别为 m,n的话,交互矩阵 就是一个 m 行 n 列的矩阵。此时用户的相似度可以表示为(其中 u*v 指的是向量点积): 为了避免存储这么大的稀疏矩阵,在计算用户相似度的时候一般会采用集合的方式进行计算。理论上向量之间的相似度计算公式都可以用来计算用户之间的相似度,但是会根据实际的情况选择不同的用户相似度度量方法。
from sklearn.metrics.pairwise import cosine_similarity i = [1, 0, 0, 0] j = [1, 0.5, 0.5, 0] consine_similarity([a, b])皮尔逊相关系数的公式与余弦相似度的计算公式非常的类似,首先对于上述的余弦相似度的计算公式写成求和的形式,其中rui ,rvi分别表示用户 u 和用户 v 对商品 i 是否有交互(或者具体的评分值): 如下是皮尔逊相关系数计算公式,减去了用户 u 和用户 v 交互的所有商品交互数量或者具体评分的平均值。 相比余弦相似度,皮尔逊相关系数通过使用用户的平均分对各独立评分进行修正,减小了用户评分偏置的影响。
from scipy.stats import pearsonr i = [1, 0, 0, 0] j = [1, 0.5, 0.5, 0] pearsonr(i, j)基于用户的协同过滤,简称User CF,原理是当一个用户A需要个性化推荐的时候, 我们可以先找到和他有相似兴趣的其他用户, 然后把那些用户喜欢的, 而用户A没有听说过的物品推荐给A。
UserCF算法主要包括两个步骤:
基于相似性度量的方法找出与目标用户兴趣相似的用户找到这个集合中的用户喜欢的, 且目标用户没有听说过的物品推荐给目标用户。以下图作为一个例子:
应用UserCF算法的两个步骤:
首先根据前面的这些打分情况(或者说已有的用户向量)计算一下Alice和用户1, 2, 3, 4的相似程度, 找出与Alice最相似的n个用户根据这n个用户对物品5的评分情况和与Alice的相似程度会猜测出Alice对物品5的评分, 如果评分比较高的话, 就把物品5推荐给用户Alice, 否则不推荐。关于结果的预测有如下几种办法:
利用用户相似度和相似用户的评价加权平均获得用户的评价预测 利用该物品的评分与此用户的所有评分的差值进行加权平均,这时候考虑到了有的用户内心的评分标准不一的情况定义数据集
similarity_matrix = pd.DataFrame(np.zeros((len(users), len(users))), index=[1, 2, 3, 4, 5], columns=[1, 2, 3, 4, 5]) # 遍历每条用户-物品评分数据 for userID in users: for otheruserId in users: vec_user = [] vec_otheruser = [] if userID != otheruserId: for itemId in items: # 遍历物品-用户评分数据 itemRatings = items[itemId] # 这也是个字典 每条数据为所有用户对当前物品的评分 if userID in itemRatings and otheruserId in itemRatings: # 说明两个用户都对该物品评过分 vec_user.append(itemRatings[userID]) vec_otheruser.append(itemRatings[otheruserId]) # 这里可以获得相似性矩阵(共现矩阵) similarity_matrix[userID][otheruserId] = np.corrcoef(np.array(vec_user), np.array(vec_otheruser))[0][1] #similarity_matrix[userID][otheruserId] = cosine_similarity(np.array(vec_user), np.array(vec_otheruser))[0][1]计算用户相似性矩阵
"""计算前n个相似的用户""" n = 2 similarity_users = similarity_matrix[1].sort_values(ascending=False)[:n].index.tolist() # [2, 3] 也就是用户1和用户2计算前n个相似的用户
"""计算最终得分""" base_score = np.mean(np.array([value for value in users[1].values()])) weighted_scores = 0. corr_values_sum = 0. for user in similarity_users: # [2, 3] corr_value = similarity_matrix[1][user] # 两个用户之间的相似性 mean_user_score = np.mean(np.array([value for value in users[user].values()])) # 每个用户的 打分平均值 weighted_scores += corr_value * (users[user]['E']-mean_user_score) # 加权分数 corr_values_sum += corr_value final_scores = base_score + weighted_scores / corr_values_sum print('用户Alice对物品5的打分: ', final_scores) user_df.loc[1]['E'] = final_scores user_df计算最终得分
User-based算法存在两个重大问题:
数据稀疏性:大型的电子商务推荐系统一般有非常多的物品,用户可能买的其中不到1%的物品,不同用户之间买的物品重叠性较低,导致算法无法找到偏好相似的用户。算法扩展性:基于用户的协同过滤需要维护用户相似度矩阵以便快速的找出Topn相似用户, 该矩阵的存储开销非常大,存储空间随着用户数量的增加而增加,不适合用户数据量大的情况使用。基于物品的协同过滤(ItemCF)的基本思想是预先根据所有用户的历史偏好数据计算物品之间的相似性,然后把与用户喜欢的物品相类似的物品推荐给用户。比如物品a和c非常相似,因为喜欢a的用户同时也喜欢c,而用户A喜欢a,所以把c推荐给用户A。
基于物品的协同过滤算法主要分为两步:
计算物品之间的相似度根据物品的相似度和用户的历史行为给用户生成推荐列表(购买了该商品的用户也经常购买的其他商品)依旧以上图为例;
基于物品的协同过滤算法步骤:
首先计算一下物品5和物品1, 2, 3, 4之间的相似性找出与物品5最相近的n个物品根据Alice对最相近的n个物品的打分去计算对物品5的打分情况计算物品的相似矩阵
"""得到与物品5相似的前n个物品""" n = 2 similarity_items = similarity_matrix['E'].sort_values(ascending=False)[:n].index.tolist() # ['A', 'D'] """计算最终得分""" base_score = np.mean(np.array([value for value in items['E'].values()])) weighted_scores = 0. corr_values_sum = 0. for item in similarity_items: # ['A', 'D'] corr_value = similarity_matrix['E'][item] # 两个物品之间的相似性 mean_item_score = np.mean(np.array([value for value in items[item].values()])) # 每个物品的打分平均值 weighted_scores += corr_value * (users[1][item]-mean_item_score) # 加权分数 corr_values_sum += corr_value final_scores = base_score + weighted_scores / corr_values_sum print('用户Alice对物品5的打分: ', final_scores) user_df.loc[1]['E'] = final_scores user_df得到与物品5相似的前n个物品, 计算出最终得分来
对用户u推荐N个物品记为 R(u), 令用户u在测试集上喜欢的物品集合为 T(u), 那么召回率定义为: 在用户真实购买的影片里面, 模型真正预测出了多少, 考察的是模型推荐的全面性。
在推荐的所有物品中, 用户真正看的有多少, 这个考察的是模型推荐的准确性。为了提高准确率, 模型需要把非常有把握的才对用户进行推荐, 所以这时候就减少了推荐数量, 而这往往损失了全面性, 真正预测出来的会非常少,所以实际应用中应该综合考虑两者的平衡。
覆盖率反映了推荐算法发掘长尾的能力, 覆盖率越高, 说明推荐算法越能将长尾中的物品推荐给用户。 该覆盖率表示最终的推荐列表中包含多大比例的物品。如果所有物品都被给推荐给至少一个用户, 那么覆盖率是100%。
用推荐列表中物品的平均流行度度量推荐结果的新颖度。 如果推荐出的物品都很热门, 说明推荐的新颖度较低。 由于物品的流行度分布呈长尾分布, 所以为了流行度的平均值更加稳定, 在计算平均流行度时对每个物品的流行度取对数。
协同过滤推荐算法给我们带来便利的同时,也存在一些问题,在实际应用过程中我们经常会遇到,以下就存在的一些典型的问题进行了分析。
推荐系统面临的问题中最大的问题就是数据稀疏性问题,它会影响推荐系统推荐的准确度,在个性化推荐系统中,协同过滤是最常用的技术,数据稀疏性影响了协同过滤的结果,因为在很多推荐系统中只有很小一部分评分,当在评分很小的情况下,推荐的准确度也会下降。
目前来说解决数据稀疏问题最好的算法是降维技术,比如奇异值SVD分解。降维技术的关键是通过原始矩阵通过计算来求其低维度的相似来降低矩阵的维度,有一点弊端就是数据量大的时候运算成本很高,好在最近几年云计算发展迅猛,这些计算量都可以放在运动,来弥补计算量的问题,除了降维技术之外人口统计过滤也是解决数据稀疏性问题的很好的方法,人口统计过滤是通过用户资料的对比找到用户相似,然后通过相似的用户来进行推荐,这种方式可以解决数据量很稀疏的情况下使用。
冷启动问题也被认作为推荐系统面临的问题中关键之一。冷启动产生原因是新用户进入系统没有用户行为数据,所以就不存在收集用户偏好的过程,进而也就很难进行有效的推荐。解决用户冷启动的问题可以采用上一小节中的人口统计过滤,其针对于冷启动也会有很好的效果,除此之外只能通过业务上调整去改变并获得用户的一些资料,从而进行有效推荐,具体的业务有利用用户注册信息、社交网络挖掘、启用用户信息。
具体做法是通过用户信息进行用户分类,利用社交网络导入用户的好友关系,然后通过好友关系来进行相关推荐,还可以通过用户的首次访问不立即给推荐反馈结果,而是通过引导页用户填写用户感兴趣的内容,然后通过这些收集到的准确信息来进行准确的推荐,一般我们会通过引导用户填写比较有代表性、区分性以及多样性的内容去进行选择,比如在豆瓣FM中,一般会采用热门精选的音乐以及分组好的音乐来给用户进行选择。解决内容冷启动问题可以通过物品的信息来解决新物品的推荐问题,一般会采用物品标签进行推荐,通过抽象出新物品的标签以及利用老物品的标签进行匹配,匹配成功就进行相关度的推荐。而系统的冷启动可以通过专家发挥专家的作用,在系统冷启动环节中,可以引入专家的知识,利用专家的知识构建起物品的相关度表,然后通过表格进行相关度的分析进行推荐。
推荐系统中通过推荐算法获得之后,因为用户之前没有足够多的对物品进行评分,有时候很难掌握用户的各方面兴趣和需求,这就会导致出现过拟合现象,这一类现象就是推荐系统中的扩展性问题,这类问题对于推荐系统的体验上是一个很大的问题。
扩展性问题在实际应用中是无可避免的,其中受数据集大小的扩展,数据完整性等问题的限制,对于数据完整性的问题,通常是引入随机性,使算法收敛到全局最优或者逼近全局最优,但是推荐系统运行过程是动态变化的,同时也会受冷启动影响,用户/对象/喜好数据达到一定规模时,性能这个时候也会存在一些瓶颈,这个时候的大数据处理和算法的可扩展性成为推荐算法技术需要实施并迫切需要解决的问题。
协同过滤算法存在的问题之一就是泛化能力弱, 即协同过滤无法将两个物品相似的信息推广到其他物品的相似性上。 导致的问题是热门物品具有很强的头部效应, 容易跟大量物品产生相似, 而尾部物品由于特征向量稀疏, 导致很少被推荐。 比如下面这个例子: A, B, C, D是物品, 看右边的物品共现矩阵, 可以发现物品D与A、B、C的相似度比较大, 所以很有可能将D推荐给用过A、B、C的用户。 但是物品D与其他物品相似的原因是因为D是一件热门商品, 系统无法找出A、B、C之间相似性的原因是其特征太稀疏, 缺乏相似性计算的直接数据。 所以这就是协同过滤的天然缺陷:推荐系统头部效应明显, 处理稀疏向量的能力弱。
为了解决这个问题,同时增加模型的泛化能力,2006年,矩阵分解技术(Matrix Factorization,MF) 被提出,该方法在协同过滤共现矩阵的基础上,使用更稠密的隐向量表示用户和物品,挖掘用户和物品的隐含兴趣和隐含特征,在一定程度上弥补协同过滤模型处理稀疏矩阵能力不足的问题。
推荐系统在推荐的过程中还会存在隐私问题、噪声问题、解释性问题、合理性、新颖性等等,这些问题在推荐系统中很有挑战性,但是解决这些问题出现的同时也会改变推荐准确度,所以我们需要权衡这些问题和推荐之间的联系,目前很多算法都有在改进相关的问题,改进的措施也是多维度的。
UserCF的适用情况:用户少, 物品多, 时效性较强的场合 ItemCF的适用情况:物品少,用户多,用户兴趣固定持久, 物品更新速度不是太快的场合
