推薦系統是近些年非常火的技術,不管是電商類軟體還是新聞類app,都號稱有精準的推薦系統能給你推送你最感興趣的內容。現象級的資訊類app“今日頭條”就得益於此成為了勢頭非常猛的一款產品。本文就針對推薦系統講述一些相關概念和實踐經驗。
首先需要明確的就是推薦系統的目標,一般來說不外乎以下幾個:
- 使用者滿意性:首當其衝的,推薦系統主要就是為了滿足使用者的需求,因此準確率是評判一個推薦系統好壞的最關鍵指標。
- 多樣性:雖然推薦系統最主要還是滿足使用者的興趣,但是也要兼顧內容的多樣性,對於權重不同的興趣都要做到兼顧。
- 新穎性:使用者看到的內容是那些他們之前沒有聽說過的物品。簡單的做法就是在推薦列表去掉使用者之前有過行為的那些內容。
- 驚喜度:和新穎性類似,但新穎性只是使用者沒看到過的但是確實是和他行為是相關的,而驚喜度是使用者既沒有看過和他之前的行為也不相關,但使用者看到後的確是喜歡的。
- 實時性:推薦系統要根據使用者的上下文來實時更新推薦內容,使用者的興趣也是隨著時間而改變的,需要實時更新。
- 推薦透明度:對於使用者看到的最終結果,要讓使用者知道推薦此內容的原因。比如,“買過這本書的人同時也買過”、"你購買過的xx和此商品類似"。
- 覆蓋率:挖掘長尾內容也是推薦系統很重要的目標。因此,推薦的內容覆蓋到的內容越多越好。
基於這些目標,推薦系統包括四種推薦方式:
- 熱門推薦:就是熱門排行榜的概念。這種推薦方式不僅僅在IT系統,在平常的生活中也是處處存在的。這應該是效果最好的一種推薦方式,畢竟熱門推薦的物品都是位於曝光量比較高的位置的。
- 人工推薦:人工干預的推薦內容。相比於依賴熱門和演算法來進行推薦。一些熱點時事如世界盃、nba總決賽等就需要人工加入推薦列表。另一方面,熱點新聞帶來的推薦效果也是很高的。
- 相關推薦:相關推薦有點類似於關聯規則的個性化推薦,就是在你閱讀一個內容的時候,會提示你閱讀與此相關的內容。
- 個性化推薦:基於使用者的歷史行為做出的內容推薦。也是本文主要講述的內容。
其中,前三者是和機器學習沒有任何關係的,但卻是推薦效果最好的三種方式。一般說來,這部分內容應該佔到總的推薦內容的80%左右,另外20%則是對長尾內容的個性化推薦。
個性化推薦系統
個性化推薦是機器學習應用的一個典型場景。在本質上和搜尋引擎是一樣的,同樣是為了解決資訊過載的問題。搜尋引擎某種意義上也是一個個性化推薦系統,但是其輸入特徵是可以從搜尋關鍵字直接可以得到的。而一般的推薦系統,輸入特徵則是需要機器學習才能得到。
個性化推薦系統一般由日誌系統、推薦演算法、內容展示UI三部分組成。
- 日誌系統:這是推薦系統的輸入源,是一個推薦系統所有資訊的源頭。
- 推薦演算法:這是推薦系統的核心,根據輸入資料得出最終的推薦結果的具體過程就在這裡。
- 內容展示UI:對於推薦結果如何展示,也是一個值得權衡的地方。以更好地滿足推薦系統的目標,並能更好的收集使用者的行為資訊等。
其中,個性化推薦中最為核心的推薦演算法,目前比較流行的有以下幾種:
- 基於內容的推薦:根據內容本身的屬性(特徵向量)所作的推薦。
- 基於關聯規則的推薦:“啤酒與尿布”的方式,是一種動態的推薦,能夠實時對使用者的行為作出推薦。是基於物品之間的特徵關聯性所做的推薦,在某種情況下會退化為物品協同過濾推薦。
- 協同過濾推薦:與基於關聯規則的推薦相比是一種靜態方式的推薦,是根據使用者已有的歷史行為作分析的基礎上做的推薦。可分為物品協同過濾、使用者協同過濾、基於模型的協同過濾。其中,基於模型的協同又可以分為以下幾種型別:基於距離的協同過濾;基於矩陣分解的協同過濾,即Latent Factor Model(SVD);基於圖模型協同,即Graph,也叫社會網路圖模型。
個性化推薦系統的典型架構如下圖所示:
線上業務系統的日誌接入資料高速公路,再由資料高速公路迅速運轉到離線資料處理平臺和線上流計算平臺;離線資料處理平臺週期性地以批處理方式加工過去一段時間的資料,得到人群標籤和其他模型引數,存放在快取記憶體中,供線上業務系統使用,與此同時,線上流計算平臺實時對線上的日誌資料做處理,對離線計算出的資料進行補充、修正等;線上業務系統綜合離線特徵和線上特徵使用一定的邏輯得到輸出供業務使用,產生的日誌流入資料高速公路。
基於此框架,個性化推薦系統的典型流程如下所示:
可知,一個推薦系統主要有以下模組組成:
- 使用者行為日誌:此部分主要是使用者行為日誌的儲存,屬於資料統計的一部分, 儲存在hive中。在此不做贅述。
- 資料ETL-1:將使用者日誌轉換為推薦演算法所需要的資料格式。
- 推薦演算法:是個性化推薦最主要的部分,包括通過使用者行為計算相關內容以及推薦結果等。
- 資料ETL-2: 將推薦演算法得到的結果進一步加工為儲存模組的輸入資料。
- 使用者畫像儲存:儲存使用者的偏好以及行為資料,如對內容關鍵字的偏好、點選過哪些內容等。
- 推薦結果儲存:儲存各種推薦演算法產生的推薦結果,可以分為兩部分:{使用者 : itemList}推薦結果,為使用者推薦的內容列表;{item : itemList}推薦結果,與item相關的內容列表。
- 服務呼叫模組:整合推薦結構,對外提供提供推薦的呼叫介面。
資料ETL-1
對原始的使用者行為等資料進行清洗、加工,如欄位、屬性、格式化等,作為下一步推薦演算法的輸入。
推薦演算法
對於個性化推薦系統來說,推薦演算法應該是其最核心的部分。目前有很多流行的演算法,比如:
- 基於內容和使用者畫像的推薦:此種演算法,可見之前的一篇文章:www.rowkey.me/blog/2016/0…。
- 基於矩陣分解的推薦: 基於SVD/ALS演算法對使用者進行內容推薦。相比起SVD,ALS更加適合解決稀疏矩陣的問題。Spark mlib中已經整合了對als演算法的實現,需要做的就是在etl-1中把資料轉換為als需要的資料格式以及調整als演算法的各種引數。這裡有一篇文章比較具體地描述瞭如何使用spark來做基於ALS的推薦:colobu.com/2015/11/30/…。
- 使用者&物品協同過濾推薦:包括UserBased CF和ItemBased CF。對於這兩者,需要根據業務的不同來選擇不同的演算法。當使用者非常多的時候,考慮到維護使用者矩陣的成本,一般是不推薦選擇使用者協同過濾的,而對於候選item很多的時候,則不推薦使用物品協同過濾。
推薦演算法的輸出結果一般是一個使用者對應一個item列表或者是一個item對應一個item列表。此部分主要考慮的是演算法的時間複雜度,不管是哪一種演算法,一旦使用者或者內容資料上了百萬級別,都需要通過分散式計算如MapReduce、Spark等來進行解決。
推薦演算法的基本流程如下圖所示:
資料ETL-2
對推薦演算法產生的結果進行清洗、格式化等,作為下一步儲存模組的輸入。
使用者畫像儲存
儲存使用者的偏好以及行為資料等資訊。對於偏好,採用標籤量化來表示,是一種隨著時間衰減的值。對於使用者畫像,是批量寫入、實時讀取,所以儲存要著重考慮讀的效能。可以選擇使用Redis叢集作為技術方案,能夠最大滿足讀的效能,缺點是Redis的成本昂貴且不支援auto index。也可使用Hbase作為儲存,使用ElasricSearch構建二級索引,以應對根據多種維度聚集使用者的需求(比如過濾某一個標籤下的所有使用者)。
推薦結果儲存
對各種推薦演算法計算出的推薦結果的儲存。儲存空間要求大,格式複雜。對於儲存的容量和讀寫效能要求都比較高。可以選擇使用Redis叢集作為此部分的儲存方案。
服務呼叫
整合使用者畫像和推薦結果兩部分資料,向外提供推薦呼叫的介面。主要是資料庫IO呼叫開銷。
- 根據使用者id,獲取推薦的item列表。
- 根據item,獲取相關聯的item列表。
- 根據使用者id, 獲取使用者畫像。
該模組需要採取一定的策略聚合多種推薦演算法的推薦結果,直接面向業務。策略由於會隨著面向的業務不同而不同,需要可配置化。同時也提供對外暴露使用者畫像的介面,使得業務方可以使用使用者畫像做針對性的處理。可以採用RPC機制對外暴露服務介面。
需要考慮的問題
對於一個推薦系統,結合其實現目標,還有一些需要注重考慮的問題。
實時性問題
由於計算使用者、item矩陣或者進行矩陣分解是需要離線進行且比較耗時,因此協同的推薦演算法是很難達到實時性的。實時部分的推薦主要依靠基於使用者畫像的推薦來進行。最終的推薦列表是根據一定的策略對這兩部分進行聚合的結果。
時效性內容問題
時效性內容指的是那些與時間強相關的內容,比如新聞、時事等。如果一條10天前xx球員獲得冠軍的新聞現在被推薦了出來,可想使用者肯定是莫名其妙或者是很失望的。因此,對於時效性內容,需要與普通的待推薦的內容區分開,做單獨的推薦或者不走個性化推薦。
冷啟動問題
不管使用何種推薦演算法,都會面臨冷啟動問題:當使用者是新使用者,如何給使用者推薦item呢?當內容是新內容,如何推薦給使用者?
- 對於新使用者,可以採取的一種策略就是採用熱門推薦或者人工推薦,把絕大多人關心的內容推薦出來。
- 對於內容,可以將內容分為新內容池和待推薦內容池。新內容產生時,首先進入新內容池。每次推薦的時候,先從新內容池做候選推薦,並給此內容的傳播度+1,直到其傳播度大於一個閾值的時候,將其移至待推薦內容池。這樣既可以解決新內容的冷啟動問題也在一定程度上可以保證新內容的曝光量。
多樣性問題
在基於使用者畫像的推薦演算法中,取出使用者的多個標籤,然後根據相關度從不同的標籤中取不同數量的內容,這樣既兼顧了使用者的多種興趣也能夠在一定程度上解決多樣性的問題。
如:使用者具有tag:A B C D,相關度為wA wB wC wD,Total推薦為總共需要推薦的條數,那麼
RecommendList(u) = A[Total推薦 * wA] + B[Total推薦 * wB] + C[Total推薦 * wC] + D[Total推薦 * wD]複製程式碼
內容質量
不管是熱門推薦、人工推薦還是取某一標籤下的內容列表都牽扯到的一個問題就是:如何給內容排序?
當使用者對內容的喜好不一樣,可以按照興趣度來排序;但當無法區分興趣度的時候(比如:使用者是新使用者;內容都是新內容;使用者對於某一標籤下的內容興趣度一樣),可以使用內容質量來做排序。click/pv是一種評判內容質量的方式。此外,使用卷積神經網路相關演算法也可以構建內容質量模型。
驚喜問題
推薦系統的驚喜目標一直是一個難題,被稱作EE(Exploit & Explore)問題,bandit演算法是解決這個問題的一個派系,就是估計置信區間的做法,然後按照置信區間的上界來進行推薦,以UCB、LinUCB為代表的。簡單點說就是先不考慮你喜不喜歡就把質量高的內容推薦給你,後面根據使用者的行為反饋對推薦內容作調整。具體的可以參見此篇文章:推薦系統的苟且和遠方。
總結
借用推薦系統的那點事一文的幾句話做為結語:
- 實力派的【演算法工程師】往往都是ABC[always be coding],這樣的演算法工程師才能根據實際問題建立模型或者建立規則庫,是真正能解決問題的人。往往是一些有研究背景,經驗豐富的研究員,更加重視工程,因為工程架構上一些恰當合理的設計,效果往往就能遠遠高過於模型演算法優化。
- 學院派的【演算法工程師】往往是為了演算法而演算法,而不是為了解決推薦系統的問題去找最適合演算法。這也是為什麼大公司經常招了一些博士畢業的演算法工程師後,不是研究演算法而是讓他們整天在那看資料包表?【因為發現演算法沒啥好研究,只能讓他們在那看看報表找找規律了。】
- 【幾乎所有所謂的智慧推薦演算法都是花拳繡腿】
- 當一個做推薦系統的部門開始重視【資料清理,資料標柱,效果評測,資料統計,資料分析】這些所謂的髒活累活,這樣的推薦系統才會有救。
以上是推薦系統實踐的一些經驗