传统推荐系统算法(一):协同过滤(Collaborative Filtering,CF)
一、协同过滤的定义
“协同过滤”可以理解为协同大家的评价、反馈来对巨量的信息进行过滤,并筛选出目标用户可能感兴趣的信息。协同过滤主要有两种算法:
基于用户的协同过滤(UserCF):给用户推荐和他兴趣相似的其他用户喜欢的产品
基于物品的协同过滤(ItemCF):给用户推荐和他之前喜欢的物品相似的物品
二、协同过滤的通俗理解
以UserCF为例:
(1)电商网站的商品库里一共有4 件商品:游戏机、某小说、某杂志和某品
牌电视机。
(2)用户X访问该网站,网站需要决定是否向X推荐电视机,即需要预测X是否喜欢这台电视机。可以利用的数据有X对其他商品的评价以及其他客户对商品的评价。用点赞表示“好评”,踩表示“差评”。此时用户、商品、评价构成了带有标识的有向图。
(3)将该有向图转换为矩阵,该矩阵命名为共现矩阵,用户名为行坐标,商品为列坐标,用户评价作为矩阵的元素值,为方便计算,可将好评设为1,差评设为-1,无评价为0(如果用户对商品有具体评分值,则取具体评分值)。
(4)生成共现矩阵后,问题就变成了预测问好的值。协同过滤的本质就是考虑与自己兴趣相似的用户的意见。因此首先就要找到与X兴趣最相近的n个用户(Top n,n为超参数),然后综合这n个相似用户对电视机的评价来预测X对电视机的评价。
(5)在共现矩阵中可以发现,B、C和X的行向量相近,因此将B、C选为Top n(n取2)相似用户,并发现B、C对电视机的评价都是负面的。
(6)因为相似用户对电视机给出差评,所以预测X对电视机也是差评,因此该网站不会对X推荐电视机这一物品。
三、用户相似度的计算
在共现矩阵中,行向量代表一个用户对所有商品的评价,即一行行向量代表一个用户向量。那么计算用户i与用户j的相似度问题就是计算用户向量i与用户向量j的相似度,两个向量之间常见的相似度计算有如下几种:
(1)余弦相似度
余弦相似度衡量了向量i与向量j之间的夹角大小。当夹脚越小时,两个用户向量月相似。公式如下:
(2)皮尔逊相关系数
相比余弦相似度,皮尔逊相关系数通过使用用户平均分对各独立评分进行修正,减小了用户评分偏置的影响。
四、最终结果的排序
在进行完上述过程后,可以计算出用户向量间的相似程度,并选出最相似的Top n用户,基于Top n用户的已有评价来对目标用户进行预测。最常用的方法是利用用户相似度和相似用户的评价加权平均获得用户的评价预测, 用下面式子表示:
还有一种方式如下, 这种方式考虑的更加全面, 依然是用户相似度作为权值, 但后面不单纯的是其他用户对物品的评分, 而是该物品的评分与此用户的所有评分的差值进行加权平均, 这时候考虑到了有的用户内心的评分标准不一的情况, 即有的用户喜欢打高分, 有的用户喜欢打低分的情况。
在获得用户 u u u对不同物品的评价预测后, 最终的推荐列表根据预测评分进行排序得到。 至此, 基于用户的协同过滤算法的推荐过程完成。
五、UserCf的实例
在上图中,判断是否将物品5推荐给用户Alice
即预测Alice会对物品5打出4.87分,因此可以推荐。
import pandas as pd
import numpy as np
def loadData():
items={'A': {1: 5, 2: 3, 3: 4, 4: 3, 5: 1},
'B': {1: 3, 2: 1, 3: 3, 4: 3, 5: 5},
'C': {1: 4, 2: 2, 3: 4, 4: 1, 5: 5},
'D': {1: 4, 2: 3, 3: 3, 4: 5, 5: 2},
'E': {2: 3, 3: 5, 4: 4, 5: 1}
}
users={1: {'A': 5, 'B': 3, 'C': 4, 'D': 4},
2: {'A': 3, 'B': 1, 'C': 2, 'D': 3, 'E': 3},
3: {'A': 4, 'B': 3, 'C': 4, 'D': 3, 'E': 5},
4: {'A': 3, 'B': 3, 'C': 1, 'D': 5, 'E': 4},
5: {'A': 1, 'B': 5, 'C': 5, 'D': 2, 'E': 1}
}
return items,users
items, users = loadData()
item_df = pd.DataFrame(items).T
user_df = pd.DataFrame(users).T
"""计算用户相似性矩阵"""
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]
print(similarity_matrix)
"""计算前n个相似的用户"""
n = 2
similarity_users = similarity_matrix[1].sort_values(ascending=False)[:n].index.tolist() # [2, 3] 也就是用户1和用户2
"""计算最终得分"""
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
print(user_df)
UserCF算法存在两个重大问题:
(1)数据稀疏性。
一个大型的电子商务推荐系统一般有非常多的物品,用户可能买的其中不到1%的物品,不同用户之间买的物品重叠性较低,导致算法无法找到一个用户的邻居,即偏好相似的用户。这导致UserCF不适用于那些正反馈获取较困难的应用场景(如酒店预订, 大件商品购买等低频应用)
(2)算法扩展性。
基于用户的协同过滤需要维护用户相似度矩阵以便快速的找出Top n相似用户, 该矩阵的存储开销非常大,存储空间随着用户数量的增加而增加,不适合用户数据量大的情况使用。
由于UserCF技术上的两点缺陷, 导致很多电商平台并没有采用这种算法, 而是采用了ItemCF算法实现最初的推荐系统。
六、基于物品的协同过滤(ItemCF)
ItemCf通过计算共现矩阵中物品列向量的相似度得到物品之间的相似矩阵,再找到用户的历史正反馈物品的相似物品进行排序和推荐,即ItemCF算法并不利用物品的内容属性计算物品之间的相似度, 主要通过分析用户的行为记录计算物品之间的相似度, 该算法认为, 物品a和物品c具有很大的相似度是因为喜欢物品a的用户大都喜欢物品c。
具体步骤如下:
(1)基于历史数据,构建以用户(假设用户总数为m) 为行坐标,物品(物品总数为n) 为列坐标的mXn 维的共现矩阵。
(2)计算共现矩阵两两列向量间的相似性(相似度的计算方式与用户相似度的计算方式相同),构建nXn 维的物品相似度矩阵。
(3)获得用户历史行为数据中的正反馈物品列表。
(4)利用物品相似度矩阵,针对目标用户历史行为中的正反馈物品,找出相似的Top k 个物品,组成相似物品集合。
(5)对相似物品集合中的物品,利用相似度分值进行排序,生成最终的推荐列表。
继续以上面的例子来进行实例演示:
根据皮尔逊相关系数, 可以找到与物品5最相似的2个物品是item1和item4(n=2),计算最终得分: