推薦系統概述

技術小能手發表於2018-10-31

“聆忠言者眾,惟智者受益。” — 哈珀·李

許多人把推薦系統視為一種神祕的存在,他們覺得推薦系統似乎知道我們的想法是什麼。Netflix 向我們推薦電影,還有亞馬遜向我們推薦該買什麼樣的商品。推薦系統從早期發展到現在,已經得到了很大的改進和完善,以不斷地提高使用者體驗。儘管推薦系統中許多都是非常複雜的系統,但其背後的基本思想依然十分簡單。

推薦系統是什麼?

推薦系統是資訊過濾系統的一個子類,它根據使用者的偏好和行為,來向使用者呈現他(或她)可能感興趣的物品。推薦系統會嘗試去預測你對一個物品的喜好,以此向你推薦一個你很有可能會喜歡的物品。

如何構建一個推薦系統?

現在已經有很多種技術來建立一個推薦系統了,我選擇向你們介紹其中最簡單,也是最常用的三種。他們是:一,協同過濾;二,基於內容的推薦系統;三,基於知識的推薦系統。我會解釋前面的每個系統相關的弱點,潛在的缺陷,以及如何去避免它們。最後,我在文章末尾為你們準備了一個推薦系統的完整實現。

協同過濾

協同過濾,是首次被用於推薦系統上的技術,至今仍是最簡單且最有效的。協同過濾的過程分為這三步:一開始,收集使用者資訊,然後以此生成矩陣來計算使用者關聯,最後作出高可信度的推薦。這種技術分為兩大類:一種基於使用者,另一種則是基於組成環境的物品。

基於使用者的協同過濾

基於使用者的協同過濾本質上是尋找與我們的目標使用者具有相似品味的使用者。如果Jean-Pierre和Jason曾對幾部電影給出了相似的評分,那麼我們認為他們就是相似的使用者,接著我們就可以使用Jean Pierre的評分來預測Jason的未知評分。例如,如果Jean-Pierre喜歡星球大戰3:絕地武士歸來和星球大戰5:帝國反擊戰,Jason也喜歡絕地武士歸來,那麼帝國反擊戰對Jason來說是就是一個很好的推薦。一般來說,你只需要一小部分與Jason相似的使用者來預測他的評價。

9aea093257eb126a451fef3d80a3b3187ba6dc77

在下表中,每行代表一個使用者,每列代表一部電影,只需簡單地查詢這個矩陣中行之間的相似度,就可以找到相似的使用者了。

26d0264247f132008b28fcc86da7193be9e82eee

然而,基於使用者的協同過濾在實現中存在一些以下問題:

 ●  使用者偏好會隨時間的推移而改變,推薦系統生成的許多推薦可能會隨之變得過時。
 ●  使用者的數量越多,生成推薦的時間就越長。
 ●  基於使用者會導致對託攻擊敏感,這種攻擊方法是指惡意人員通過繞過推薦系統,使得特定物品的排名高於其他物品。
(託攻擊即Shilling Attack,是一種針對協同過濾根據近鄰偏好產生推薦的特點,惡意注入偽造的使用者模型,推高或打壓目標排名,從而達到改變推薦系統結果的攻擊方式)

  • 194年12月,我們小分隊在滇西北找礦。小分隊一共8人,其中4名警戰士每人配備一支衝鋒槍。一天,出發前,一位納西族老鄉搭我們的車去維西。那天路上積雪很大,雪下的路面坑窪不平,車子行駛一段就會被雪塢住。我們不得不經常下來推車。就在我們又一次下車推車的時候,一群褐黃色的東西慢慢向我們靠近。我們正驚疑、猜測時,納西族老鄉急喊:“快、快趕緊上車,是一群狼。”司機小王趕緊發動車,加大油門……但是很不幸,車輪只是在原地空轉,根本無法前進。這時狼群已靠近汽車……大家看得清清楚楚——8只狼,個個都象小牛犢似的,肚子吊得老高。戰士小吳抄起衝鋒槍,納西族老鄉一手奪下小吳的搶。比較沉著地高聲道:“不能開槍,槍一響,它們或鑽到車底下或鑽進樹林,狼群會把車胎咬壞,把我們圍起來,然後狼會嚎叫召集來更多的狼和我們拼命。”他接著說:“狼餓瘋了,它們是在找吃的,車上可有吃的?”我們幾乎同聲回答:“有。”“那就扔下去給它們吃。”老鄉像是下達命令。從來沒有經歷過這樣的事,當時腦子裡一片空白,除了緊張,大腦似乎已經不會思考問題。聽老鄉這樣說,我們毫不猶豫,七手八腳把從麗江買的臘肉、火腿還有十分珍貴的鹿子乾巴往下丟了一部分。狼群眼都紅了,興奮地大吼著撲向食物,大口的撕咬吞嚥著,剛丟下去的東西一眨眼就被吃光了。老鄉繼續命令道:“再丟下去一些!”第二批大約50斤肉品又飛出了後車門,也就一袋煙的工夫,又被8只狼分食的乾乾淨淨。吃完後8只狼整齊地坐下,盯著後車門。這時,我們幾人各個屏氣息聲,緊張的手心裡都是冷汗,甚至能夠清晰的聽到自己心跳的聲音……我們不知道能有什麼辦法令我們從狼群中突圍出去。看到這樣的情形,老鄉又發話道:“還有嗎?一點不留地丟下,想保命就別心疼這些東西了!”此時,除了緊張、害怕還有羞憤……!作為戰士,我們是有責任保護好這些物資的,哪怕犧牲自己。但是現實情況是我們的車被塢到雪地裡出不來,只能被困在車裡。我們的子彈是極有限的,一旦有狼群被召喚來,我們會更加束手無策。我們幾人相互看了一眼,遲疑片刻,誰也沒有說什麼,忍痛將車上所有的肉品,還有十幾包餅乾全都甩下車去!8只狼又是一頓大嚼。吃完了肉,它們還試探性的嗅了嗅那十幾包餅乾,但沒有吃。這時我清楚地看到狼的肚子已經滾圓,先前暴戾凶惡的目光變得溫順。其中一隻狼圍著汽車轉了兩圈,其餘7只狼沒動。片刻,那隻狼帶著狼群朝樹林鑽去……不可思議的事情發生了……不一會兒,8只狼鑽出松林,嘴裡叼著樹枝,分別放到汽車兩個後輪下面。我們簡直不敢相信自己的眼睛……這些狼的意思是想用樹枝幫我們墊起輪胎,讓我們的車開出雪窩。我激動地大笑起來……哈……哈……剛笑了兩聲,另外一個戰士忙用手捂住了我的嘴,他怕這突兀的笑聲驚毛了狼。接著,8只狼一齊鑽到車底,但見汽車兩側積雪飛揚。我眼裡滾動著淚花,大呼小王:“狼幫我們扒雪呢,趕快發動車,”車啟動了,但是沒走兩步,又打滑了。狼再次重複剛才的動作:“先往車輪下墊樹枝,然後扒雪……”。就這樣,每重複一次,汽車就前進一段,大約重複了十來次。最後一次,汽車順利地向前行了一里多地,接近了山頂。再向前就是下坡路了。這時,8只狼在車後一字排開坐著,其中一隻比其他7只狼稍稍向前。老鄉說:“靠前面的那只是頭狼,主意都是他出的。”我們激動極了,一起給狼鼓掌,並用力地向它們揮手致意。但是這8只可愛的狼對我們的舉動並沒有什麼反應,只是定定地望了望我們,然後,頭狼在前,其餘隨後,緩緩朝山上走去,消失在松林中……看完不忍思考:連凶猛的狼都懂得報恩,我們是否應該反思自身?自詡為“萬物靈長”的人類,們是不是應當讓這個世界充滿愛94年12月,我們小分隊在滇西北找礦。小分隊一共8人,其中4名警戰士每人

基於物品的協同過濾

基於物品的協同過濾過程很簡單。兩個物品的相似性基於使用者給出的評分來算出。讓我們回到Jean-Pierre與Jason的例子,他們兩人都喜歡“絕地武士歸來”和“帝國反擊戰”。 因此,我們可以推斷,喜歡第一部電影的大多數使用者也可能會喜歡第二部電影。所以,對於喜歡“絕地武士歸來”的第三個人Larry來說,”帝國反擊戰“的推薦將是有意義的。

16037781f6b648c271ad39905bc769f740e9ce67

所以,這裡的相似度是根據列而不是行來計算的(與上面的使用者-電影矩陣中所見的不同)。基於物品的協同過濾常常受到青睞,因為它沒有任何基於使用者的協同過濾的缺點。首先,系統中的物品(在這個例子中物品就是電影)不會隨著時間的推移而改變,所以推薦會越來越具有關聯性。此外,通常推薦系統中的物品都會比使用者少,這減少了推薦的處理時間。最後,考慮到沒有使用者能夠改變系統中的物品,這種系統要更難於被欺騙或攻擊。

基於內容的推薦系統

在基於內容的推薦系統中,元素的描述性屬性被用來構成推薦。“內容Content”一詞指的就是這些描述。舉個例子,根據Sophie的聽歌歷史,推薦系統注意到她似乎喜歡鄉村音樂。因此,系統可以推薦相同或相似型別的歌曲。更復雜的推薦系統能夠發現多個屬性之間的關係,從而產生更高質量的推薦。例如,音樂基因組計劃(Music Genome Project)根據450個不同的屬性將資料庫中的每支歌曲進行分類。該專案為Pandor的歌曲推薦提供技術支援。(Pandor提供線上音樂流媒體服務,類似Spolify)

基於知識的推薦系統

基於知識的推薦系統在物品購買頻率很低的情況下特別適用。例如房屋、汽車、金融服務甚至是昂貴的奢侈品。在這種情況下,推薦的過程中常常缺乏商品的評價。基於知識的推薦系統不使用評價來作出推薦。相反,推薦過程是基於顧客的需求和商品描述之間的相似度,或是對特定使用者的需求使用約束來進行的。這使得這種型別的系統是獨一無二的,因為它允許顧客明確地指定他們想要什麼。關於約束,當應用時,它們大多是由該領域的專家實施的,這些專家從一開始就知道該如何實施這些約束。例如,當使用者明確指出在一個特定的價格範圍內尋找一個家庭住宅時,系統必須考慮到這個使用者規定的約束。

推薦系統中的冷啟動問題

推薦系統中的主要問題之一是最初可用的評價數量相對較小。當新使用者還沒有給電影打分,或者一部新的電影被新增到系統中時,我們該怎麼做呢?在這種情況下,應用傳統的協同過濾模型會更加困難。儘管基於內容和基於知識的推薦演算法在面臨冷啟動問題時比協同過濾更具有魯棒性,但基於內容和基於知識並不總是可用的。因此,一些新方法,比如混合系統,已經被設計出用來解決這個問題了。

混合推薦系統

文章到目前為止所介紹的不同型別的推薦系統都各有優劣,他們根據不同的資料給出推薦。 一些推薦系統,如基於知識的推薦系統,在資料量有限的冷啟動環境下最為有效。其他系統,如協同過濾,在有大量資料可用時則更加有效。在多數情況下,資料都是多樣化的,我們可以為同一任務靈活採用多種方法。 因此,我們可以結合多種不同技術的推薦來提高整個系統的推薦質量。許多的組合性技術已經被探索出來了,包括:

 ●  加權:為推薦系統中的每種演算法都賦予不同的權重,使得推薦偏向某種演算法
 ●  交叉:將所有的推薦結果集合在一起展現,沒有偏重
 ●  增強:一個系統的推薦將作為下一個系統的輸入,迴圈直至最後一個系統為止
 ●  切換:隨機選擇一種推薦方法

混合推薦系統中的一個最有名的例子是於2006至2009年舉行的Netflix Price演算法競賽。這個競賽的目標是將Netflix的電影推薦系統Cinematch的演算法準確率提高至少10%。Bellkor’s Pragmatix Chaos團隊用一種融合了107種不同演算法的方案將Cinematch系統的推薦準確率提高了10.06%,並最終獲得了100萬美元獎金。你可能會對這個例子中的準確率感到好奇,準確率其實就是對電影的預測評分與實際評分接近程度的度量。

推薦系統與AI?

推薦系統常用於人工智慧領域。推薦系統的能力 – 洞察力,預測事件的能力和突出關聯的能力常被用於人工智慧中。另一方面,機器學習技術常被用於實現推薦系統。例如,在Arcbees,我們使用了神經網路和來自IMdB的資料成功建立了一個電影評分預測系統。神經網路可以快速地執行復雜的任務並輕鬆地處理大量資料。通過使用電影列表作為神經網路的輸入,並將神經網路的輸出與使用者評分進行比較,神經網路可以自我學習規則以預測特定使用者的未來評分。

專家建議

在我讀過許多資料中,我注意到有兩個很重要的建議經常被推薦系統領域內的專家提及。第一,基於使用者付費的物品進行推薦。當一個使用者有購買意願時,你就可以斷定他的評價一定是更具有相關性與準確的。第二,使用多種演算法總是比改進一種演算法要好。Netflix Prize競賽就是一個很好的例子。

實現一個基於物品的推薦系統

下面的程式碼演示了實現一個基於物品的推薦系統是多麼的簡單與快速。所使用的語言是Python,並使用了Pandas與Numpy這兩個在推薦系統領域中最流行的庫。所使用的資料是電影評分,資料集來自MovieLens。

第一步:尋找相似的電影

1.讀取資料

import pandas as pd

import numpy as np

 

ratings_cols = [`user_id`, `movie_id`, `rating`]

ratings = pd.read_csv(`u.data`, sep=`t`, names=ratings_cols, usecols=range(3))

 

movies_cols = [`movie_id`, `title`]

movies = pd.read_csv(`u.item`, sep=`|`, names=movies_cols, usecols=range(2))

 

ratings = pd.merge(ratings, movies)


2.構造使用者的電影矩陣


movieRatings = ratings.pivot_table(index=[`user_id`],columns=[`title`],values=`rating`)


3.選擇一部電影並生成這部電影與其他所有電影的相似度

starWarsRatings = movieRatings[`Star Wars (1977)`]

 

similarMovies = movieRatings.corrwith(starWarsRatings)

similarMovies = similarMovies.dropna()

df = pd.DataFrame(similarMovies)


4.去除不流行的電影以避免生成不合適的推薦

ratingsCount = 100

movieStats = ratings.groupby(`title`).agg({`rating`[np.size, np.mean]})

popularMovies = movieStats[`rating`][`size`] >= ratingsCount

movieStats[popularMovies].sort_values([(`rating`, `mean`)], ascending=False)[:15]



5.提取與目標電影相類似的流行電影

df = movieStats[popularMovies].join(pd.DataFrame(similarMovies, columns=[`similarity`]))

df.sort_values([`similarity`], ascending=False)[:15]


第二步:基於使用者的所有評分做出推薦

1.生成每兩部電影之間的相似度,並只保留流行電影的相似度

userRatings = ratings.pivot_table(index=[`user_id`],columns=[`title`],values=`rating`)

corrMatrix = userRatings.corr(method=`pearson`, min_periods=100)


2.對於每部使用者看過並評分過的電影,生成推薦(這裡我們選擇使用者0)


myRatings = userRatings.loc[0].dropna()

simCandidates = pd.Series()

for i in range(0, len(myRatings.index)):

    #取出與評分過電影相似的電影

    sims = corrMatrix[myRatings.index[i]].dropna()

    #以使用者對這部電影的評分高低來衡量它的相似性

    sims = sims.map(lambda xx * myRatings[i])

    #將結果放入相似性候選列表中

    simCandidates = simCandidates.append(sims)

 

simCandidates.sort_values(inplace = True, ascending = False)


3.將所有相同電影的相似度加和


simCandidates = simCandidates.groupby(simCandidates.index).sum()

simCandidates.sort_values(inplace = True, ascending = False)



4.只保留使用者沒有看過的電影


filteredSims = simCandidates.drop(myRatings.index)


如何更進一步?

在上面的例項中,Pandas與我們的CPU足以處理MovieLens的資料集。然而,當資料集變得更龐大時,處理的時間也會變得更加漫長。因此,你應該轉為使用具有更強大處理能力的解決方案,如Spark或MapReduce。

我希望我已經成功讓你看到,實現一個簡單而有效的推薦系統中並沒有什麼複雜之處。如果你有任何問題,不要猶豫,直接評論就好了。

原文釋出時間為:2018-10-28

本文來自雲棲社群合作伙伴“網際網路架構師”,瞭解相關資訊可以關注“網際網路架構師”。


相關文章