簡單的協同過濾演算法程式碼 推薦系統
推薦系統 簡單的協同過濾程式碼
參考:https://blog.csdn.net/u012332571/article/details/52206055部落格
問題:7個人對不同電影的評分,根據評分計算使用者的相似度
資料為:
critics={ '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} }
一. 基於使用者的協同過濾
通俗地說,就是找到與目標使用者相似的使用者,推薦給目標使用者相似使用者喜歡的物品。
1.計算使用者相似度
1.1歐幾里得距離
d=∑(p1−p2)2‾‾‾‾‾‾‾‾‾‾‾‾√
(注:p1代表使用者1對電影v的評分,p2代表使用者2對電影v的評分,其中v 是使用者1和使用者2共同評分的電影)
在實際應用中,希望相似度越大,返回的值越大,並且值控制在0到1之間,因此我們取函式值加1的倒數(加1是為了防止除0的情況)
輸入:#1.歐幾里得距離 def sim_distance(prefs,person1,person2): #建立一個空集合用來儲存使用者1和使用者2都有的電影的評分 si = {} for item in prefs[person1]: if item in prefs[person2]: si[item] = 1 #如果兩個人沒有共同的評分,則返回0 if len(si) == 0: return 0 #計算所有距離的和(差值的平方和) sum_of_squares = sum([pow(prefs[person1][item]-prefs[person2][item],2) for item in prefs[person1] if item in prefs[person2]]) return 1 / (1 + sqrt(sum_of_squares))#分子上加1,是為了防止分母為0
import recommendations
critics = recommendations.critics
print(recommendations.sim_distance(critics,'Lisa Rose','Gene Seymour'))
可得,兩使用者的相似度為0.29429805508554946
1.2皮爾遜相關係數
採用和參考部落格中不一樣的公式,得到相同的結果。
def sim_pearson2(prefs,p1,p2): #另一種方法也行 si = {} ci = {} di = {} for item in prefs[p1]: ci[item] = 1 n1 = len(ci) for item in prefs[p2]: di[item] = 1 n2 = len(di) for item in prefs[p1]: if item in prefs[p2]: si[item] = 1 n = len(si) if n == 0: return 1 # 為什麼不是0? # 對所有偏好求和(也是對兩者共同的電影來說) u1 = sum([prefs[p1][item] for item in ci]) / n1 u2 = sum([prefs[p2][item] for item in di]) / n2 # 乘積之和 num = sum([(prefs[p1][item] - u1) * (prefs[p2][item] - u2) for item in si]) # 計算皮爾遜相關係數 s1 = sum([pow((prefs[p1][item] - u1),2) for item in si]) s2 = sum([pow((prefs[p2][item] - u2), 2) for item in si]) den = sqrt(s1) * sqrt(s2) if den == 0: return 0 r = num / den return r
同理,也可得到兩個使用者的相似度。
2.根據使用者相似度,求與某一使用者相近的其他使用者的前幾名(從字典裡選取品味最近的使用者)
def topMatches(prefs,person,n = 5,similarity = sim_pearson):
#求引數使用者和其他所有使用者的相似係數
scores =[(similarity(prefs,person,other),other) for other in prefs if other != person]
#對列表進行排序,評價值最高者排在最前面
scores.sort()
scores.reverse()
return scores[0:n]
輸入:print(recommendations.topMatches(critics, 'Toby', n=3))
得到和使用者“Toby”相似的前3位使用者:
[(0.9912407071619299, 'Lisa Rose'), (0.9244734516419049, 'Mick LaSalle'), (0.8934051474415647, 'Claudia Puig')]
3.根據品味相近的使用者給目標使用者推薦沒有看過的電影(利用所有相似使用者的加權平均,為某人提供建議)
def getRecommendations(prefs,person,similarity = sim_pearson):
totals = {}
simSums = {}
for other in prefs:
if other == person:continue
sim = similarity(prefs,person,other)
#忽略相似值為零或者小於零的情況
if sim <= 0: continue
for item in prefs[other]:
#只對自己沒有看過的電影評價
if item not in prefs[person] or prefs[person][item] == 0:
#相似度*評價值
totals.setdefault(item,0)#.setdefault:如果鍵在字典中,返回這個鍵所對應的值。如果鍵不在字典中,向字典中插入這個鍵,返回值為0.
totals[item] += prefs[other][item]*sim
#相似度之和
simSums.setdefault(item,0)
simSums[item]+= sim
#建立一個列表,列表裡面是person沒有看過的電影和評分
rangkings=[(totals / simSums[item],item) for item, totals in totals.items()]
#排序
rangkings.sort()
rangkings.reverse()
return rangkings
輸入:print(recommendations.getRecommendations(critics,'Michael Phillips'))
得到對使用者Michael Phillips推薦的電影和評分
[(3.5, 'You, Me and Dupree'), (1.5, 'Just My Luck')]
二、基於物品的協同過濾
1.可以把使用者和電影反過來,和尋找品味相近的使用者一樣,來尋找類似的電影。
def transformPrefs(prefs):
result={}
for person in prefs:
for item in prefs[person]:
result.setdefault(item,{})
result[item][person] = prefs[person][item]
return result
輸入:print(recommendations.transformPrefs(critics)) 檢視轉換後的資料
2.給使用者推薦物品的時候,通過物品相似度,還有相似物品的評分,通過公式計算,就能得出推薦使用者未購買或者評分的物品評分
#基於物品的協同過濾
def calculateSimilarItems(prefs,n=10):
#與這些電影最為相近的其他所有電影
result = {}
#以物品為中心對偏好矩陣實施倒置處理
itemPrefs = transformPrefs(prefs)
c = 0
for item in itemPrefs:
scores = topMatches(itemPrefs,item,n=n,similarity=sim_distance)
result[item] = scores
return result
def getRecommendedItems(prefs,itemMatch,user):
userRatings = prefs[user]
scores ={}
totalSim={}
#迴圈遍歷與當前物品相近的物品
for (item, rating) in userRatings.items():
for (similarity, item2) in itemMatch[item]:
# 如果該使用者已經對當前物品做出過評價,就忽略
if item2 in userRatings: continue
# 評價值與相似度的加權之和
scores.setdefault(item2, 0)
scores[item2] += similarity * rating
# 全部相似度之和
totalSim.setdefault(item2, 0)
totalSim[item2] += similarity
# 將每個和值除以加權和,求平均值
rankings = [(score / totalSim[item], item) for item, score in scores.items()]
# 排序
rankings.sort()
rankings.reverse()
return rankings
輸入:
itemsim = recommendations.calculateSimilarItems(critics)
print(itemsim)
輸出:{'Snakes on a Plane': [(0.3483314773547883, 'Lady in the Water'), (0.32037724101704074, 'The Night Listener'), (0.3090169943749 。。。。。
輸入:
itemsim = recommendations.calculateSimilarItems(critics)
print(recommendations.getRecommendedItems(critics, itemsim, 'Toby'))
輸出:[(3.1667425234070894, 'The Night Listener'), (2.9366294028444355, 'Just My Luck'), (2.8687673926264674, 'Lady in the Water')]
有關運用該程式碼處理MovieLens資料的,下次再寫有關部落格。