1. 程式人生 > >基於物品的協同過濾(item-based collaborative filtering)

基於物品的協同過濾(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

然後,

TotalSim.Sum=i=1niii=(1)
#來了個新使用者,獲得推薦
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>推薦排名第一的電影