1. 程式人生 > >基於內容推薦的個性化新聞閱讀實現(二):基於SVD的推薦演算法

基於內容推薦的個性化新聞閱讀實現(二):基於SVD的推薦演算法

一、前言

SVD前面已經說了好多次了,先不論其資訊檢索被宣稱的各種長處如何如何,在此最主要的作用是將稀疏的term-doc矩陣進行降維,當一篇篇文章變成簡短的向量化表示後,就可以用各種科學計算和機器學習演算法進行分析處理了。
之前的推薦演算法的設計是用的最大熵估計,他和諸如樸素貝葉斯、邏輯迴歸等,本質就是根據文章詞彙資訊把文章作為一個二類歸類問題來解決的。根據自己以前的經驗,這種方法是最簡單,效果也還是比較理想的,而且相比現在設計的越來越複雜的演算法,也有堅實的數理做依據的。
這次,嘗試一個新的推薦方式,我的思路是這樣的:如果你SVD分解降維後取n_topics=2,那麼這些文章最後就都對映成了二維向量,可以把這些二維向量看作平面中的座標,那麼每篇文章其實就是這個平面上的點了。一般來說,文章越相似,那麼他們的向量就越相近,然後對映到座標空間中兩者的歐式距離也就越短。反應到我們的推薦閱讀中,如果一個人可能有幾個興趣點,那麼他喜歡的文章在空間位置就應該聚成以這幾個簇的形式展現出來。當然n_topics=2肯定不能用在實踐中應用的,否則會丟失大量的特徵資訊,但是很容易將這個想法推廣到多維的超平面上,基本原理都是一樣的。
這個方法在實現中考慮到的缺陷有:浮點向量沒法儲存到資料庫,只能駐留記憶體和dump到檔案系統了;計算速度肯定比貝葉斯要慢很多,但是絕大多數推薦系統不都是定時進行資料線下計算線上載入的麼;目前只考慮點讚的,不考慮踩的負樣本的影響了,或許這也不是什麼優劣勢,負樣本本來就可以在所有樣本中取樣來進行平衡。

二、演算法實現流程

具體實現流程步驟設計如下:
(1) 設定n_topics引數,然後對歷史的文章進行SVD奇異值分解,生成LSI空間引數;
(2) 針對每一個使用者,取出其歷史點讚的文章,用LSI浮點向量表示後,把每篇文章兩兩計算其餘弦值相似度,形成各個文章間的相似度矩陣;
(3) 設定閾值範圍factor(比如0.5,其值也可以根據後面的計算結果動態反饋修改),然後遍歷所有點讚的文章,如果其閾值範圍內的點贊文章數目達到三篇及以上,那麼建立其為一個興趣點,平均化興趣點中所有文章的特徵向量得到中心特徵向量,其興趣權重正比於其興趣點中所包含的文章的數目;
(4) 細心的讀者可能發現,這樣肯定會產生很多個覆蓋有重疊的興趣點。可不是嘛!所以這裡還需要一步額外的迭代:選取權重最高的興趣點,確定之後將包含的所有文章排除掉,然後再在剩餘的文章中選擇最高權重的興趣點,依次下來直到沒有新的興趣點或者達到指定要求的興趣點,迭代結束;
(5) 每當有當日新的文章到來,通過之前SVD引數計算其在當前空間中的表示向量,然後按照其到各個興趣點特徵向量距離並乘上興趣點的權重,得到推薦分數,以最高分數作為這篇文章的最終推薦分數。

三、效果評價

通常演算法的評價一般需要用標註資料和預測推薦進行驗證。一天幾百篇文章我也懶得過一遍再標註了,就偷點懶,用之前最大熵估計的推薦分數和本文演算法的推薦結果進行一個對比吧!

感覺效果還不是特別的明顯,是資料的原因麼?

四、後注

這只是自己憑空想出來的推薦,自我覺得還是有道理的吧。
專案程式碼還是老地方readmeinfo,因為詞ID用gensim的庫做了,所以執行新程式碼前記得刪除dump快取目錄所有的快取資料,同時資料庫的site_rcd這個表記得新增double型別的recsvd欄位。
本來打算部署到我的512M的VPS上的,但是上面服務太多已經很慢了,後面居然給我報記憶體錯誤,看來MaxEnt和SVD都是消耗記憶體的大戶啊,所以上面的資料是把伺服器的資料導下來用本地筆記本跑的結果,當然這些資料我也上傳到程式碼庫了,感興趣的可以自己驗證!同時由於荒蕪了一段時間(最主要還是移動端UI做爛了,自己都懶得看啊),歷史好評資料不夠多,所以就產生了一個興趣點,不排除多個興趣點的情況下還有Bug,歡迎反饋!

真心想,如果有足夠資料,做個協同過濾CF還是多爽的,不然枉費搞過推薦系統了~

本文完!