基於用戶的協同過濾算法(UserCF)
基於用戶的協同過濾算法是通過用戶的歷史行爲數據發現用戶對物品的喜好,並對這些喜好進行度量和打分,根據不同用戶對相同物品的偏好計算用戶之間的相似度,在有相同喜好的用戶間進行推薦。
步驟:
- 找到與目標用戶興趣相似的用戶集合
- 找到這個集合中用戶喜歡的並且目標用戶沒有購買過的物品推薦給目標用戶
優點:
- 能夠在用戶間相互協助,根據用戶對物品的打分的相似性對用戶進行分類
- 所有用戶都能從鄰居用戶的反饋評價中得意
- 容易挖掘目標用戶潛在的新興趣
缺點:
- 稀疏性:一個大型的電商平臺有非常多的物品,用戶購買的物品很少,不同用戶之間買的物品重疊率較低,導致無法找到目標用戶的鄰居。
- 冷啓動問題:在一個新物品首次出現的時候,沒有用戶對它進行打分,無法對其進行預測和推薦,而且在新物品出現早期,用戶打分少,推薦準確率不高
- 特殊用戶的喜好和任何一類羣體都不同,無法找到目標用戶的鄰居用戶進行協同推薦,用戶是“善變”的,用戶喜好可能會發生變化
基於物品的協同過濾算法(ItemCF)
基於物品的協同過濾給用戶推薦那些和用戶之前喜歡的物品相似的物品,ItemCF不利用物品的內容相似計算物品的相似度,它是通過分析用戶行爲記錄計算物品的相似度,物品A和B相似是因爲喜歡物品A的用戶也喜歡物品B。
步驟:
- 計算物品之間的相似度
- 根據物品的相似度和用戶歷史行爲給用戶生成推薦列表
優點:
- 計算性能高,通常用戶數量遠大於物品數量
- 可預先計算保留,物品不“善變”
協同過濾中冷啓動問題
- 用戶冷啓動:新用戶因爲沒有在物品上留下行爲數據,自然無法得知用戶的喜好,不能給新用戶推薦物品,這時一般需要藉助用戶的背景資料,或者引導用戶選擇,或者暫時用熱門啓動替代個性化推薦(給用戶推薦排行榜單),在線推薦系統可以做到在用戶產生行爲數據後立馬更新推薦列表。
- 物品冷啓動:對於一個物品推薦類似物品,因爲新物品還沒有用戶行爲數據,自然也就沒辦法通過協同過濾的方式進行推薦,一般對物品的描述進行文本分析,或者採用主題模型,或者打標籤,或者推薦排行榜單。
兩種推薦算法的比較
基於用戶的協同過濾算法實現
import numpy as np
class Recommand():
def __init__(self, users):
"""
初始化
"""
self.users = users
def pearson(self, username, user):
"""
:Input: 目標用戶和其他用戶
:return: 目標用戶與其他用戶的皮爾森係數
"""
x = []
y = []
for movie, score in self.users[username].items():
if movie in self.users[user].keys():
x.append(self.users[username][movie])
y.append(self.users[user][movie])
x = np.array(x)
y = np.array(y)
sum_xy = ((x-x.mean())*(y-y.mean())).sum()
sum_x = np.sqrt(((x-x.mean())*(x-x.mean())).sum())
sum_y = np.sqrt(((y-y.mean())*(y-y.mean())).sum())
return sum_xy/(sum_x*sum_y)
def nearstUser(self, username, k):
"""
:Input: 目標用戶和最近鄰個數
:return: 排好序的前k個鄰居的皮爾森係數
"""
distances = {}
for user in self.users.keys():
if user != username:
distances[user] = self.pearson(username, user) # 計算皮爾森係數
distances = sorted(distances.items(), key=lambda x:x[1], reverse=True) # 排序
return distances[:k]
def recommand(self, username, k):
"""
:Input: 目標用戶和最近鄰個數
:return: 推薦結果及預測的評分
"""
recommand_list={} # 推薦的電影
s = 0
for user, score in dict(self.nearstUser(username, k)).items(): # 最近的k個用戶
s += score
for movies, scores in self.users[user].items(): # 推薦的用戶的電影列表
if movies not in self.users[username].keys(): # 當前username沒有看過
recommand_list.setdefault(movies, 0)
if movies in recommand_list.keys(): # 添加到推薦列表中
recommand_list[movies] = recommand_list[movies]+score*scores
for k,v in recommand_list.items():
recommand_list[k] = np.round(v/s, 1)
return sorted(recommand_list.items(), key=lambda x:x[1], reverse=True) # 對推薦的結果按照電影評分排序
if __name__=='__main__':
users = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5, 'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5, 'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5, 'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0, 'You, Me and Dupree': 3.5},
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0, 'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0, 'The Night Listener': 4.5, 'Superman Returns': 4.0, 'You, Me and Dupree': 2.5},
'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0, 'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0, 'You, Me and Dupree': 2.0},
'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0, 'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}
}
usercf = Recommand(users)
result = usercf.recommand('Toby', 2)
print('爲目標用戶%s推薦的結果:%s'% ('Toby', result))
爲目標用戶Toby推薦的結果:[(‘The Night Listener’, 3.0), (‘Lady in the Water’, 2.7), (‘Just My Luck’, 2.5)]