基於物品的協同過濾(item-based collaborative filtering)
姓名:wagsyang
日期:星期四, 08. 十二月 2016 08:26下午
簡介
本書是集體智慧程式設計一書的學習筆記。
之前我們已經完成了基於使用者的協同過濾的推薦演算法,它的思想是將所有的使用者和自己對比,顯然對於小資料集還是可以忍受的,但是對於大量或巨量的使用者資料集,這種實時進行相似度計算即耗時又耗力。
有沒有更好的計算方法呢?有,就是我們不再基於使用者,我們基於物品。基於使用者的時候,來了一個人,就同剩下的全部人比較,實時運算傷不起。基於物品的時候,來了一個人,我們就看他最近看過什麼或買過什麼(物品),我們計算該物品同剩下的其它全部物品進行相似度比較,找出相似度高的推薦給他。
這裡你又會說,這不是一樣要實時運算嗎。其實不然,我們可以提前就計算好每個物品和它相似度高的物品,倉庫裡的每個物品都這樣算一遍,把結果儲存起來。來了個人的時候,我們根據它買過看過的物品,在儲存的資料裡呼叫這些買過看過物品相似度高的物品(已經計算過)推薦給他就好了。這樣不就好了。
資料集和相似度準則
同基於使用者的協同過濾
#基於物品的推薦
critics={\
'Lisa Rose':{'lady in 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 water':3.0,'snakes on a plane':3.5,'just my luck':1.5,'superman returns':5.0,'you,me and dupree':3.5,'the night listener':3.0},
'Michael Phillips':{'lady in 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,'superman returns':4.0,'the night listener':4.5},
'Mick Lasalle':{'lady in water':3.0,'snakes on a plane':4.0,'just my luck':2.0,'superman returns':3.0,'you,me and dupree':2.0,'the night listener':3.0},
'Jack Matthews':{'lady in water':3.0,'snakes on a plane':4.0,'superman returns':5.0,'you,me and dupree':3.5,'the night listener':3.0},
'Toby':{'snakes on a plane':4.5,'superman returns':4.0,'you,me and dupree':1.0}}
from math import sqrt
#歐幾里德距離
def sim_distance(prefs,p1,p2):
si={}
# find common items
for item in prefs[p1]:
if item in prefs[p2]: si[item]=1
if len(si)==0: return 0
#cal the distance
sum_of_sqr=sum([pow(prefs[p1][item]-prefs[p2][item],2) for item in si])
return 1/(1+sqrt(sum_of_sqr))
#皮爾遜相關度
def sim_pearson(prefs,p1,p2):
si={}
for item in prefs[p1]:
if item in prefs[p2]: si[item]=1
if len(si)==0: return 0
sum1=sum([prefs[p1][item] for item in si])
sum2=sum([prefs[p2][item] for item in si])
sum1sq=sum([pow(prefs[p1][item],2) for item in si])
sum2sq=sum([pow(prefs[p2][item],2) for item in si])
psum=sum([prefs[p1][item]*prefs[p2][item] for item in si])
num=psum-sum1*sum2/len(si)
den=sqrt((sum1sq-pow(sum1,2)/len(si))*(sum2sq-pow(sum2, 2)/len(si)))
if den==0:
return 0
return num/den
基於使用者——>基於物品
可以程式碼複用,只需要將人和物品對調即可。
#物品與人員互相調換
def transformprefs(prefs):
result={}
for person in prefs:
for item in prefs[person]:
result.setdefault(item,{})
# 人、物對調
result[item][person]=prefs[person][item]
return result
#最相關的N個person,這裡僅僅是函式定義,實際傳入引數為物品
def topmatchs(prefs,person,n=5,similarity=sim_pearson):
scores=[(similarity(prefs,person,other),other) for other in prefs if other!=person]
scores.sort(reverse=True)
return scores[0:n]
#構建物品比較資料集合,即,每個item有n個最相關的其它item
def calculatesimilaryitems(prefs,n=10):
itemsim={}
itemprefs=transformprefs(prefs)
c=0
for item in itemprefs:
c+=1.0
if c%100==0:print('%d/%d' %(c,len(itemprefs)))
scores=topmatchs(itemprefs,item,n=n,similarity=sim_pearson)
itemsim[item]=scores
return itemsim
獲得推薦
以上部分可以單獨提前執行,並存儲結果。現在來了一個使用者,它有若干買過或看過的物品,我們呼叫儲存的資料庫,找到與他買過看過的物品有很高相關度的物品。
例如:我們看過Snake,Superman,Dupree,並有我們給的評分。基於我們看過的這三個電影,查詢儲存資料庫,找到與每個電影(Snake,Superman,Dupree)的相似度高的其它所有或部分排名靠前的相關電影,這裡是Night,Lady,Luck。
影片 | 評分 | Night | R.xNight | Lady | R.xLady | Luck | R.xLuck |
---|---|---|---|---|---|---|---|
Snakes | 4.5 | 0.182 | 0.818 | 0.222 | 0.999 | 0.105 | 0.474 |
Superman | 4.0 | 0.103 | 0.412 | 0.091 | 0.363 | 0.065 | 0.258 |
Dupree | 1.0 | 0.148 | 0.148 | 0.4 | 0.4 | 0.182 | 0.182 |
Total | 1.378 | 1.762 | 0.941 | ||||
Sim.sum | 0.433 | 0.713 | 0.352 | ||||
Total/Sim.Sum | 3.183 | 2.473 | 2.598 |
然後,
#來了個新使用者,獲得推薦
def getrecommendations(prefs,itemsim,user):
totalsim={}
simsum={}
for item,ratio in prefs[user].items():
for similarity,item2 in itemsim[item]:
if item2 in prefs[user]: continue
totalsim.setdefault(item2,0)
totalsim[item2]+=similarity*ratio
simsum.setdefault(item2,0)
simsum[item2]+=similarity
rankings=[(total/simsum[item],item) for item ,total in totalsim.items()]
rankings.sort(reverse=True)
return rankings
總結
一個電影
根據相似度準則> 這個電影的相關電影及其相關度該網站中的每個電影> 每個電影的相關電影及其相關度異步計算存儲> 電影相關性資料庫我&我看過的電影
查找數據庫> 得到相關電影及其相關度按公式(1)排名> 推薦排名第一的電影