推荐系统的召回算法(一)—— 协同过滤法(基于用户)
??姍姍來遲的第二篇博客,最近在了解有關(guān)推薦系統(tǒng)方面的基本知識(shí)和算法,先總結(jié)其中一類經(jīng)典常用的算法——協(xié)同過濾法。網(wǎng)上已有很多介紹其原理的好文章,所以本文用較多篇幅來寫一些自身對算法實(shí)現(xiàn)的理解和疑惑,希望有經(jīng)驗(yàn)的小伙伴能夠解惑,感激不盡!
??寫的比較倉促,如有描述或理解錯(cuò)誤,敬請指出,望共同進(jìn)步~
目錄
- 為何做推薦系統(tǒng)
- 召回和排序
- 協(xié)同過濾法—基于用戶(UserCF)
- UserCF原理
- 實(shí)現(xiàn)過程
- Python代碼
- 結(jié)語
為何做推薦系統(tǒng)
??先介紹下推薦系統(tǒng)中經(jīng)常出現(xiàn)的兩個(gè)術(shù)語:User 和 Item,即用戶和物品,這里的物品可以是書籍、電影、新聞、視頻等。
??什么情況下需要推薦系統(tǒng)?——信息過載且用戶沒有明確的需求。簡單理解信息過載就是Item數(shù)量非常多,用戶一時(shí)半會(huì)兒不知道想要什么,這時(shí)候推薦系統(tǒng)就可以主動(dòng)向用戶提供他們可能感興趣的物品。所以在做推薦系統(tǒng)前需要了解兩件事兒:
(1)平臺(tái)上Item的數(shù)量是否過多;如果數(shù)量不大,可以用分類目錄的形式對Item進(jìn)行分門別類,更方便用戶找到適合自己的Item.
(2)用戶每次使用平臺(tái)時(shí),自身的需求是否明確.
??以抖音app為例子,里面的短視頻千千萬,用戶一般并不清楚自己具體想看什么,推薦就成了留住用戶的最好方式,所以抖音的主界面就是個(gè)推薦場景(其實(shí)還有個(gè)搜索界面);還有淘寶app和云音樂app等,里面的推薦場景隨處可見。
召回和排序
??回歸正題,推薦系統(tǒng)一般包含兩個(gè)算法部分:召回階段(recall)和 排序階段(rank)。先說排序階段的作用,也是傳統(tǒng)機(jī)器學(xué)習(xí)、深度學(xué)習(xí)在推薦系統(tǒng)中發(fā)揮威力的地方,它們可以預(yù)測用戶對物品的點(diǎn)擊率、轉(zhuǎn)化率等(類似廣告中CTR模型),再以特定的規(guī)則進(jìn)行排序后展示給用戶,更符合規(guī)則的物品做優(yōu)先展示。但是不可能把所有的物品一次性喂入排序模型做預(yù)測排序(數(shù)量太多,算完用戶都跑了),所以召回階段的作用就是把所有物品做初步的篩選形成一個(gè)物品候選集,再進(jìn)入排序階段。
??排序階段里往往都是高大上的模型,似乎直接決定推薦結(jié)果,其實(shí)召回階段產(chǎn)生的Item候選集也會(huì)對最終推薦結(jié)果產(chǎn)生很大影響。比如小明購買過一個(gè)水杯,然后召回階段產(chǎn)生的候選集幾乎由杯子這一類的物品組成,導(dǎo)致排序階段輸出的Top-N物品全是五花八門的杯子。。。顯然這樣的召回策略缺乏多樣性,使得排序模型無論多精確都無法擺脫只推薦杯子的結(jié)局。
??本文重點(diǎn)介紹召回階段最常見的一類算法——協(xié)同過濾法(Collaborative Filtering),做推薦的小伙伴們都應(yīng)該很熟悉吧。相比ML、DL這些模型算法,CF幾乎沒有什么深?yuàn)W的數(shù)學(xué)原理,注重的是背后原理和思想。
協(xié)同過濾法—基于用戶(UserCF)
??協(xié)同過濾法屬于召回階段的算法,簡單有效的特點(diǎn)使其仍未過時(shí),現(xiàn)有的各大推薦場景中都能看到這類算法的影子。基本思想就是基于用戶或物品的相似度做推薦,下面就介紹其中一種。
UserCF原理
??基于用戶的協(xié)同過濾法,基本思想是尋找用戶A的相似用戶B,把用戶B接觸過的物品b推薦給用戶A。借鑒《推薦系統(tǒng)實(shí)踐》一書中的說法,該算法主要包括兩個(gè)步驟:
??(1)找到和目標(biāo)用戶A興趣相似的用戶集合;
??(2)找到這個(gè)集合中的用戶喜歡的,且目標(biāo)用戶A沒有發(fā)生行為的物品推薦給目標(biāo)用戶A。
??如何衡量用戶的相似度呢?首先確定計(jì)算相似度所需的用戶數(shù)據(jù)來源,我第一反應(yīng)就是用戶的畫像數(shù)據(jù)(性別、身高、收入等),但是仔細(xì)想想畫像數(shù)據(jù)并不能完全反映一個(gè)用戶在平臺(tái)里的興趣偏好。相比之下,用戶在平臺(tái)上的行為數(shù)據(jù)更能體現(xiàn)其在平臺(tái)中的興趣偏好,也更適用于計(jì)算用戶相似度,比如抖音中的點(diǎn)贊、頁面停留時(shí)長;淘寶中的瀏覽、加購、購買、評分等行為數(shù)據(jù)。
??其次確定采用何種相似度指標(biāo),以下列舉幾個(gè)常見的相似度計(jì)算公式:
??(一)對于停留時(shí)長、評分等連續(xù)型行為數(shù)據(jù)
??假設(shè)用戶a和用戶b對所有Item的評分(停留時(shí)長)向量分別為 A 和 B,其中A=(a1,a2,...,an)A=(a_{1},a_{2},...,a_{n})A=(a1?,a2?,...,an?), B=(b1,b2,...,bn)B=(b_{1},b_{2},...,b_{n})B=(b1?,b2?,...,bn?),則有:
余弦相似度
cos?A,B?=A?B∣∣A∣∣×∣∣B∣∣=∑i=1naibi∑i=1n(ai)2×∑i=1n(bi)2cos\left \langle A,B \right \rangle={\frac {A \cdot B} {||A||\times||B||}}={\frac {\sum_{i=1}^{n}a_{i} b_{i}} {\sqrt {\sum_{i=1}^{n}\left (a_{i} \right )^2} \times \sqrt{\sum_{i=1}^{n}\left (b_{i} \right )^2}}}cos?A,B?=∣∣A∣∣×∣∣B∣∣A?B?=∑i=1n?(ai?)2?×∑i=1n?(bi?)2?∑i=1n?ai?bi??
??最初用于文本相似度的計(jì)算。從二維和三維的角度來看,該指標(biāo)就是兩個(gè)向量間夾角的余弦值,取值范圍為[0,1],越接近1說明兩個(gè)向量越相似。
??公式中分母做了類似標(biāo)準(zhǔn)化(去量綱)的操作,圖中可看出該指標(biāo)以向量間的夾角來衡量相似度,所以忽略了向量本身的模長。
歐式距離(Euclidean)
d(A,B)=(a1?b1)2+(a2?b2)2+...+(an?bn)2=(∑i=1n∣ai?bi∣2)1/2d(A,B)=\sqrt {(a_{1}-b_{1})^2+(a_{2}-b_{2})^2+...+(a_{n}-b_{n})^2}=(\sum_{i=1}^{n} {|a_{i}-b_{i}|^2})^{1/2}d(A,B)=(a1??b1?)2+(a2??b2?)2+...+(an??bn?)2?=(i=1∑n?∣ai??bi?∣2)1/2
??歐氏距離是非常直觀的距離指標(biāo),屬于閔可夫斯基距離(Minkowski)的一種特殊形式,類似的還有曼哈頓距離(Manhattan)、切比雪夫距離(Chebyshev),這些距離指標(biāo)在K-means、KNN等算法中一般都有詳細(xì)介紹。
??可將歐氏距離做變型:11+d(A,B)\frac {1} {1+d(A,B)}1+d(A,B)1?,用該值衡量A,B向量的相似度更合適。相比余弦相似度,歐氏距離從向量各個(gè)分量間的差值體現(xiàn)兩者距離(差異)。
Pearson相關(guān)系數(shù)
cor(A,B)=E[(A?μA)(B?μB)]σA?σB=1n∑i=1n(ai?aˉ)(bi?bˉ)1n∑i=1n(ai?aˉ)2×1n∑i=1n(bi?bˉ)2cor\left( A,B\right)=\frac {E[(A-\mu_{A})(B-\mu_{B})]} {\sigma_{A}\cdot\sigma_{B}}=\frac {\frac {1} {n}\sum_{i=1}^{n}{(a_{i}-\bar{a})(b_{i}-\bar{b})}} {\sqrt{\frac {1} {n}\sum_{i=1}^{n}{(a_{i}-\bar{a})^2}}\times\sqrt{\frac {1} {n}\sum_{i=1}^{n}{(b_{i}-\bar{b})^2}}}cor(A,B)=σA??σB?E[(A?μA?)(B?μB?)]?=n1?∑i=1n?(ai??aˉ)2?×n1?∑i=1n?(bi??bˉ)2?n1?∑i=1n?(ai??aˉ)(bi??bˉ)?
其中aˉ=1n∑i=1nai\bar{a}=\frac {1} {n}\sum_{i=1}^{n}{a_{i}}aˉ=n1?∑i=1n?ai?,bˉ=1n∑i=1nbi\bar{b}=\frac {1} {n}\sum_{i=1}^{n}{b_{i}}bˉ=n1?∑i=1n?bi? 。
??這是統(tǒng)計(jì)學(xué)中常用的相關(guān)性指標(biāo),用于描述兩個(gè)變量間的線性相關(guān)性。在余弦相似度的基礎(chǔ)上,對分子分母均做中心化(去均值)處理,所以也被稱為調(diào)整余弦相似度。
??個(gè)人對采用這個(gè)指標(biāo)有些疑惑:首先相關(guān)系數(shù)取值為[-1,1],如果cor(A,B)<0cor(A,B)<0cor(A,B)<0,說明用戶A和用戶B對item的某行為數(shù)據(jù)呈負(fù)相關(guān)關(guān)系,假設(shè)該行為是瀏覽時(shí)長,然后把用戶B瀏覽時(shí)長短的item推給用戶A?還是只截取與用戶A相關(guān)系數(shù)為正的用戶,作為推薦給A的相似用戶集?
??(二)對于購買、瀏覽等離散型行為數(shù)據(jù)
??假設(shè)用戶A和用戶B的購買(瀏覽等)物品集合分別為N(a)和N(b),則有:
Jaccard相似度
wAB=∣N(a)∩N(b)∣∣N(a)∪N(b)∣w_{AB}=\frac {|N(a) \cap N(b)|} {|N(a) \cup N(b)|}wAB?=∣N(a)∪N(b)∣∣N(a)∩N(b)∣?
余弦相似度
wAB=∣N(a)∩N(b)∣∣N(a)∣∣N(b)∣w_{AB}=\frac {|N(a) \cap N(b)|} {\sqrt{|N(a)||N(b)|}}wAB?=∣N(a)∣∣N(b)∣?∣N(a)∩N(b)∣?
??以上兩個(gè)指標(biāo)中,冷門物品和熱門物品對用戶相似度的權(quán)重是相同的,但實(shí)際上兩個(gè)用戶對冷門物品的行為更能說明他們興趣的相似度——《推薦系統(tǒng)實(shí)踐》,所以John S. Breese提出了一種改進(jìn)的相似度指標(biāo)。
改進(jìn)的相似度
wAB=∑i∈N(a)∩N(b)1log(1+∣N(i)∣)∣N(a)∣∣N(b)∣w_{AB}=\frac {\sum_{i \in N(a)\cap N(b)}^{} \frac {1} {log\left (1+\left |N(i)\right | \right)}} {\sqrt {|N(a)||N(b)|}}wAB?=∣N(a)∣∣N(b)∣?∑i∈N(a)∩N(b)?log(1+∣N(i)∣)1??
??其中N(i)N(i)N(i)為對物品i有過購買(瀏覽等)行為的用戶集,1log(1+∣N(i)∣)\frac {1} {log(1+|N(i)|)}log(1+∣N(i)∣)1?表示物品i對相似度的影響,不難發(fā)現(xiàn)物品的購買人群越多(越熱門),其對相似度的影響越小,反之冷門物品的影響越大;所以改進(jìn)后的指標(biāo)更能刻畫用戶間的個(gè)人偏好相似度。
本節(jié)總結(jié)和思考
??1、一般平臺(tái)埋點(diǎn)數(shù)據(jù)返回的行為字段有很多,可以計(jì)算用戶間多個(gè)行為的相似度w1、w2...wNw_{1}、w_{2}...w_{N}w1?、w2?...wN?,比如購買行為的相似度、瀏覽時(shí)長的相似度等等,那么如何整合這些相似度來得到最終的候選集呢?
(a)利用每個(gè)相似度指標(biāo)wi,i∈1,2,...Nw_{i},i \in {1,2,...N}wi?,i∈1,2,...N,產(chǎn)生NNN個(gè)候選集,取并集作為召回階段最終輸出的候選集;
(b)根據(jù)實(shí)際業(yè)務(wù)對每個(gè)相似度賦予合適的權(quán)重ri∈[0,1]r_{i}\in [0,1]ri?∈[0,1],比如認(rèn)為購買行為比瀏覽行為更反應(yīng)出用戶的興趣偏好,那么用購買行為數(shù)據(jù)算出的相似度指標(biāo)權(quán)重應(yīng)該更大,再通過加權(quán)平均的方式w=∑i=1nriwiw=\sum_{i=1}^{n}{r_{i}w_{i}}w=∑i=1n?ri?wi?作為最終用戶間的相似度,然后再得到輸出的候選集.
【第一種得到的候選集感覺更偏重多樣性,第二種做法中如果各權(quán)重定的好,找相似用戶似乎更準(zhǔn)確;所以不知道用哪種方式整合兩種相似度,或者說實(shí)際應(yīng)用中還有更好的方案.】
??2、各類指標(biāo)各有優(yōu)劣,可根據(jù)對具體業(yè)務(wù)的理解進(jìn)行取舍,如果不同指標(biāo)對最終的推薦結(jié)果影響不大,優(yōu)先采取計(jì)算時(shí)間短的。(對于高維稀疏向量,余弦相似度的計(jì)算速度應(yīng)該比較快.)
??3、實(shí)際中離散型的行為數(shù)據(jù)應(yīng)該更常見吧,業(yè)務(wù)平臺(tái)初期可能沒有太多的行為數(shù)據(jù)埋點(diǎn),但肯定有最基本的交易日志數(shù)據(jù)(買賣交易平臺(tái)),就可以從購買行為來計(jì)算用戶的相似度,后期再增加新的行為埋點(diǎn)數(shù)據(jù)。
??4、冷啟動(dòng)問題,計(jì)算相似度的前提是用戶發(fā)生過行為,所以對于新用戶而言,該算法暫時(shí)會(huì)失效。列舉兩種常見的解決辦法:
(a)直接向新用戶推送近期的熱門物品。畢竟受大部分用戶喜愛的物品能大概率激發(fā)新用戶的興趣,或者說被新用戶厭惡的概率很低,但顯然缺乏個(gè)性化;
(b)當(dāng)新用戶第一次進(jìn)入平臺(tái)時(shí),讓其選擇自身感興趣的Item類別。我記得CSDN就有這個(gè)功能,給出了Java開發(fā)、人工智能等幾個(gè)選項(xiàng),然后根據(jù)新用戶的選項(xiàng)做博客推送。
【也有很多平臺(tái)會(huì)接入第三方的數(shù)據(jù)庫得到新用戶在其他平臺(tái)(如vx、微博等)的畫像數(shù)據(jù),用于解決冷啟動(dòng)問題。】
實(shí)現(xiàn)過程
??推薦系統(tǒng)需要具備一定的實(shí)時(shí)性,即用戶進(jìn)入業(yè)務(wù)平臺(tái)后會(huì)立即給出對應(yīng)的推薦結(jié)果,或者推薦結(jié)果隨著用戶的行為時(shí)時(shí)更新。比如在淘寶app中用戶剛瀏覽過某物品后,類似的商品下一秒就出現(xiàn)在推薦列表中,用戶不僅覺得體驗(yàn)很棒,還會(huì)驚嘆這個(gè)系統(tǒng)好 “ 智能 ”的樣子 。
??為了盡量實(shí)現(xiàn)上述流程的實(shí)時(shí)性,一般會(huì)把算法中涉及到的復(fù)雜對象提前計(jì)算好,需要時(shí)再做調(diào)用可大大降低在線的推薦耗時(shí)。
用戶物品倒排表
??當(dāng)給定一個(gè)用戶id時(shí),如何快速獲取其近期發(fā)生過行為的Item集合?每次都用SQL語句獲取感覺效率不高,所以需提前離線構(gòu)建一個(gè)用戶物品倒排表。
用戶相似矩陣
??輸入用戶id,都要獲取該用戶與所有其他用戶的相似度,為避免大量重復(fù)的計(jì)算,可以離線計(jì)算好用戶間的相似度矩陣,并設(shè)置合適的時(shí)間間隔進(jìn)行更新。
步驟:
離線部分:
(1)構(gòu)建用戶物品倒排表并進(jìn)行存儲(chǔ);
(2)計(jì)算好用戶的相似度矩陣并進(jìn)行存儲(chǔ);
在線部分:
輸入:用戶A的唯一id
(1)根據(jù)相似度矩陣找出用戶A對應(yīng)的其他用戶相似度,排序并截取前k個(gè)相似用戶id;
(2)利用用戶物品倒排表找出k個(gè)相似用戶的物品集;
(3)對(2)中得到的物品集做進(jìn)一步過濾,如刪除A已購的物品、已下架的物品等,得到最終候選集a;
輸出:物品候選集a
Python代碼
數(shù)據(jù)說明
??代碼所用數(shù)據(jù)是隨機(jī)產(chǎn)生的成交數(shù)據(jù),字段包括用戶id(user_id)和物品id(item_id),所以只有一種行為數(shù)據(jù)。數(shù)據(jù)包含5000+個(gè)不同用戶,2100+個(gè)不同物品,成交記錄一共有8w條。【數(shù)據(jù)有點(diǎn)簡潔,畢竟本文重點(diǎn)是了解算法應(yīng)用的細(xì)節(jié)…】
用戶物品倒排表(user_item.py)
??這里我用字典(dict)來儲(chǔ)存用戶物品倒排表,形如:{‘user 1’:[‘item 1’,‘item2’,…],‘user 2’:[‘item 2’,‘item 3’,…],…} 。
用戶相似矩陣(user_similar.py)
??代碼里用了離散行為數(shù)據(jù)情況下的余弦相似度公式,以下兩類情況把相似度直接標(biāo)0:(1)多數(shù)用戶間的已購物品無交集;(2)用戶間的相似度為1,說明兩者的已購物品集完全相同,沒有可以互相推薦的物品,后續(xù)通過對相似度進(jìn)行排序查找相似用戶時(shí)應(yīng)該排除此類用戶,所以提前把這類相似度標(biāo)0。
【說實(shí)話,代碼中對用戶id做遍歷的兩層for循環(huán)讓我有點(diǎn)慌了,一時(shí)半會(huì)兒也想不到優(yōu)化的方法…】
計(jì)算推薦物品候選集(User_CF.py)
??這里將UserCF寫成函數(shù)的形式進(jìn)行調(diào)用,即輸入一個(gè)用戶后返回相應(yīng)的推薦物品候選集。【應(yīng)用主程序?qū)懗山涌谑遣皇歉奖闫渌Z言的調(diào)用?】
注:以上代碼分文件跑會(huì)報(bào)錯(cuò)!
本節(jié)總結(jié)和思考
??1、顯然在主文件User_CF.py中,用戶物品倒排表user_item和用戶相似度矩陣user_similar作為其全局變量參與其中,那么3個(gè)文件的變量如何共享呢?
【目前本人只想到利用數(shù)據(jù)庫存儲(chǔ)和讀取user_item和user_similar的方式進(jìn)行共享。但是用戶物品倒排表是字典的形式,不知道轉(zhuǎn)化成什么樣的表格形式存入數(shù)據(jù)庫?主程序讀取后還要轉(zhuǎn)回成字典形式,想想都覺得麻煩…】
??2、應(yīng)用程序文件User_CF.py如何實(shí)現(xiàn)實(shí)時(shí)計(jì)算?
(a)把所有用戶的候選集提前算好存入數(shù)據(jù)庫,然后Java實(shí)時(shí)調(diào)用做推薦展示(暫時(shí)忽略排序階段);
(b)把python代碼寫成接口供Java調(diào)用,有需求時(shí)才調(diào)用計(jì)算推薦結(jié)果.
【第一種方案其實(shí)不是實(shí)時(shí)計(jì)算,提前一次性算好,而且感覺資源浪費(fèi),可能大部分用戶的推薦結(jié)果沒用到;第二種方案看上去更理想,不過對算法代碼的優(yōu)化要求貌似更高,畢竟要控制計(jì)算耗時(shí)在ms級(jí)別,所以上線時(shí)一般會(huì)采用哪種方式呢或者有更好的方法?】
??3、用戶物品倒排表和用戶相似度矩陣能否做到實(shí)時(shí)更新?
【很多文章中都提到相似度矩陣是離線計(jì)算的,這就意味著如果用戶相似度矩陣不更新,UserCF計(jì)算得到的Item候選集就不會(huì)變,所以不能只用UserCF做召回。】
結(jié)語
??有很多指標(biāo)可以評測召回算法的好壞,比如召回率、覆蓋率、準(zhǔn)確率等,本文未作詳細(xì)介紹。最近處于剛接觸項(xiàng)目階段,所以文中內(nèi)容更偏重算法的落地工程方面,沒有細(xì)究算法的質(zhì)量和數(shù)學(xué)原理。
??另外文中很多本人沒想明白的地方希望有小伙伴能解惑,感激不盡!下一篇會(huì)介紹另一種常見的CF算法——基于Item的協(xié)同過濾,日期不定…
總結(jié)
以上是生活随笔為你收集整理的推荐系统的召回算法(一)—— 协同过滤法(基于用户)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Python】【setFocus】焦点
- 下一篇: 推荐系统 | 威尔逊区间法