3_基于用戶的協(xié)同過濾方法

1 直觀描述

用戶A有幾個“關(guān)系很好”的朋友 B、C、D,通常B或C或D買了什么東西的話,A也要跟著買。昨天,B新買了一個物品 g ,而用戶A之前也從沒見過物品 g ,那么,購物平臺就將 g 推薦給A。

2 基于用戶協(xié)同過濾的步驟

⑴ 計(jì)算用戶間的相似度。

? ??\omega_{uv} =\frac{同時被用戶u和用戶v喜歡的物品數(shù)}{用戶u喜歡的物品數(shù)乘以用戶v喜歡的物品數(shù),再對乘積開根號}

⑵?預(yù)測某一用戶對物品集中他尚未進(jìn)行評分的物品的評分,并依據(jù)計(jì)算出來的評分高低來進(jìn)行推薦。也可以先對所有物品進(jìn)行評分預(yù)測,然后剔除掉已評分的物品,對剩下的物品進(jìn)行排序。

3 用戶相似度的計(jì)算

用兩個for循環(huán)遍歷user_dict中的用戶,通過集合的交集運(yùn)算,很容易得到同時被用戶u和用戶v喜歡的物品數(shù),至于每個用戶喜歡的物品數(shù),通過len()函數(shù)很容易得到,于是就得到所有的\omega_{uv} 了。

上面這種做法將會把每兩個用戶之間的相似度都算一遍,計(jì)算量太大而且也沒必要,因?yàn)樵趯?shí)際場景下,與用戶A“關(guān)系很好”的朋友的數(shù)量通常是有限的。我們將用戶A “關(guān)系很好 ”的那幾個朋友找出來并計(jì)算他們與A的相似度就行了。

這就可以用上倒排表了。所謂倒排表,指的是從用戶評分文件轉(zhuǎn)換而來的物品用戶倒排表。設(shè)倒排表為字典 T,則 T 中記錄的是各個物品被哪些用戶操作過。之后我們只計(jì)算操作過同一物品的不同用戶之間的相似度就行了,計(jì)算的方法就是:對一個物品,用for循環(huán)遍歷兩遍其用戶集。當(dāng)然,我們還需要把所有物品給遍歷一遍,這樣才能累加得到同時被用戶u和用戶v喜歡的物品數(shù)。

下面我們定義一個函數(shù)實(shí)現(xiàn)用戶相似度的計(jì)算。

def? user_similarity( user_dict ):

? ? ? ? # 構(gòu)建倒排表

? ? ? ? item_users = dict()

? ? ? ? for u, u_items in?user_dict.items():

? ? ? ? ? ? ? ? for i in u_items.keys():

? ? ? ? ? ? ? ? ? ? ? ? item_users.setdefault( i, set() )

? ? ? ? ? ? ? ? ? ? ? ? if?user_dict[u][i] > 0.0:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? item_users[ i ].add(u)? ? # 把用戶u加入到物品 i 的用戶集合中去

? ? ? ? # 上面的過程得到了倒排表?item_users

????????# 構(gòu)建用戶在物品集上的同現(xiàn)矩陣,只對出現(xiàn)在同一個用戶集里的兩個用戶進(jìn)行計(jì)算

? ? ? ? user_itemcount = dict()? ? # 記錄每個操作的物品數(shù),后面要當(dāng)做分母

? ? ? ? count = dict()? ?# 同現(xiàn)矩陣

?????????for i , i_users in?item_users.items():

? ? ? ? ? ? ? ? for u in i_users:

? ? ? ? ? ? ? ? ? ? ? ? user_itemcount.setdefault( u, 0 )

? ??????????????????????user_itemcount[u] += 1

? ? ? ? ? ? ? ? ? ? ? ? count.setdefault(u, {} )

? ? ? ? ? ? ? ? ? ? ? ? for v in i_users:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? count[u].setdefault( v, 0 )

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if u == v:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? count[u][v] += 1 / math.log( 1 + len(i_users) )??

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #?len(i_users)表示操作過物品 i 的用戶集里用戶的數(shù)目,此處對熱門物品進(jìn)行了懲罰

? ? ? ? similarity = dict()? ? # 記錄用戶相似度

? ? ? ? for u , u_users in count.items():

? ? ? ? ? ? ? ? similarity.setdefault(u, {})

? ? ? ? ? ? ? ? for v, v_u in? u_users.items():

? ? ? ? ? ? ? ? ? ? ? ? if u == v:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue

? ? ? ? ? ? ? ? ? ? ? ? similarity[u].setdefault(v, 0.0)

? ? ? ? ? ? ? ? ? ? ? ? similarity[u][v] = v_u / math.sqrt( user_itemcount [u] * user_itemcount[v] )

? ? ? ? return similarity

4 預(yù)測評分的過程

我們可以定義一個近鄰用戶數(shù) k 。在對某個用戶進(jìn)行推薦時,我們把與該用戶 “關(guān)系最好”的其它 k 個用戶所操作過的物品全部找出來,并從中剔除掉該用戶已經(jīng)操作過的物品,然后只對剩下的物品進(jìn)行評分預(yù)測。

我們先找出該用戶評價過的所有物品,假設(shè)保存在 item_of_thisuser字典里,字典的鍵為各個評價過的物品。事實(shí)上,?item_of_thisuser 很容易從原始評分文件user_dict中提取出來。

下面我們定義一個函數(shù)實(shí)現(xiàn)評分預(yù)測的過程,暫時不考慮最終的排序問題。

def prediction(thisuser, k=8):

? ? ? ? result = dict()

? ??????sort_similarity = sorted( similarity[ thisuser ].items(), key=lambda x: x[1], reverse=True)

? ? ? ? for v, wuv in?sort_similarity[0: k]:

? ? ? ? ? ? ? ? for i, r_vi in user_dict[v].items():

? ? ? ? ? ? ? ? ? ? ? ? if i in?item_of_thisuser:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue

? ? ? ? ? ? ? ? ? ? ? ? result.setdefault(i, 0)

? ? ? ? ? ? ? ? ? ? ? ? result[i] +=?r_vi *?wuv

? ? ? ? return result

5 用戶協(xié)同與物品協(xié)同的比較

從推薦場景而言,在電子商務(wù)、電影網(wǎng)站和圖書網(wǎng)站等領(lǐng)域,用戶數(shù)量遠(yuǎn)大于物品數(shù)量,且物品的數(shù)量更新速度并不快,可以考慮物品協(xié)同的方法。

對于新聞、博客等類似于信息流的領(lǐng)域,由于內(nèi)容更新頻率非常高,且內(nèi)容很容易過時,可以考慮用戶協(xié)同的方法。

用戶協(xié)同更注重社會化因素,而物品協(xié)同更注重個性化因素。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容