基於用戶的協同過濾算法

發篇老文。。。。很老的文。。。。git

什麼是推薦算法

推薦算法最先在1992年就提出來了,可是火起來其實是最近這些年的事情,由於互聯網的爆發,有了更大的數據量能夠供咱們使用,推薦算法纔有了很大的用武之地。github

最開始,因此咱們在網上找資料,都是進yahoo,而後分門別類的點進去,找到你想要的東西,這是一我的工過程,到後來,咱們用google,直接搜索本身須要的內容,這些均可以比較精準的找到你想要的東西,可是,若是我本身都不知道本身要找什麼腫麼辦?最典型的例子就是,若是我打開豆瓣找電影,或者我去買說,我實際上不知道我想要買什麼或者看什麼,這時候推薦系統就能夠派上用場了。算法

推薦算法的條件

推薦算法從92年開始,發展到如今也有20年了,固然,也出了各類各樣的推薦算法,可是無論怎麼樣,都繞不開幾個條件,這是推薦的基本條件數據庫

  • 根據和你共同喜愛的人來給你推薦
  • 根據你喜歡的物品找出和它類似的來給你推薦
  • 根據你給出的關鍵字來給你推薦,這實際上就退化成搜索算法了
  • 根據上面的幾種條件組合起來給你推薦

實際上,現有的條件就這些啦,至於怎麼發揮這些條件就是八仙過海各顯神通了,這麼多年沉澱了一些好的算法,今天這篇文章要講的基於用戶的協同過濾算法就是其中的一個,這也是最先出現的推薦算法,而且發展到今天,基本思想沒有什麼變化,無非就是在處理速度上,計算類似度的算法上出現了一些差異而已。數組

基於用戶的協同過濾算法

咱們先作個詞法分析基於用戶說明這個算法是以用戶爲主體的算法,這種以用戶爲主體的算法比較強調的是社會性的屬性,也就是說這類算法更增強調把和你有類似愛好的其餘的用戶的物品推薦給你,與之對應的是基於物品的推薦算法,這種更增強調把和你你喜歡的物品類似的物品推薦給你。app

而後就是協同過濾了,所謂協同就是你們一塊兒幫助你啦,而後後面跟個過濾,就是你們是商量事後才把結果告訴你的,否則信息量太大了。。iphone

因此,綜合起來講就是這麼一個算法,那些和你有類似愛好的小夥伴們一塊兒來商量一下,而後告訴你什麼東西你會喜歡。工具

算法描述

類似性計算

咱們儘可能不使用複雜的數學公式,一是怕你們看不懂,難理解,二是我是用mac寫的blog,公式很差畫,太麻煩了。。學習

所謂計算類似度,有兩個比較經典的算法測試

  • Jaccard算法,就是交集除以並集,詳細能夠看看我這篇文章。
  • 餘弦距離類似性算法,這個算法應用很廣,通常用來計算向量間的類似度,具體公式你們google一下吧,或者看看這裏
  • 各類其餘算法,好比歐氏距離算法等等。

無論使用Jaccard仍是用餘弦算法,本質上須要作的仍是求兩個向量的類似程度,使用哪一種算法徹底取決於現實狀況。

咱們在本文中用的是餘弦距離類似性來計算兩個用戶之間的類似度。

與目標用戶最相鄰的K個用戶

咱們知道,在找和你興趣愛好類似的小夥伴的時候,咱們可能能夠找到幾百個,可是有些是好基友,但有些只是普通朋友,那麼通常的,咱們會定一個數K,和你最類似的K個小夥伴就是你的好基友了,他們的愛好可能和你的愛好相差不大,讓他們來推薦東西給你(好比肥皂)是最好不過了。

何爲和你類似呢?簡單的說就是,好比你喜歡macbook,iphone,ipad,A小夥伴喜歡macbook,iphone,note2,小米盒子,肥皂,蠟燭,B小夥伴喜歡macbook,iphone,ipad,肥皂,潤膚霜,C女神喜歡雅詩蘭黛,SK2,香奈兒,D屌絲喜歡ipad,諾基亞8250,小霸王學習機那麼很明顯,B小夥伴和你更加類似,而C女神徹底和你不在一個檔次上,那咱們推薦的時候會把肥皂推薦給你,由於咱們以爲肥皂可能最適合你。

那麼,如何找出這K個基友呢?最直接的辦法就是把目標用戶和數據庫中的全部用戶進行比較,找出和目標用戶最類似的K個用戶,這就是好基友了。

這麼作理論上是沒什麼問題的,可是當數據量巨大的時候,計算K個基友的時間將會很是長,並且你想一想就知道,數據庫中的大部分用戶其實和你是沒有什麼交集的,所不必計算全部用戶了,只須要計算和你有交集的用戶就好了。

要計算和你有交集的用戶,就要用到物品到用戶的反查表,什麼是反查表呢?很簡單,仍是是上面那個AB小夥伴和C女神的例子,反查表就是喜歡macbook的有你,A,B,喜歡iphone的有你,B。。。就是喜歡某些物品的用戶,有了這個表,咱們就能夠看出來,和你有關係的用戶就只有A和B,D了,而C女神和你沒有任何交集,因此不用去想C了。

這樣,咱們有了A和B,D,而後就分別計算A和B,D與你的類似度,無論用哪一個類似性公式,咱們算出來都是B和你更類似(在這個例子中,通常會用Jaccard來計算,由於這些向量不是特別好餘弦化),但若是此時咱們的K設定爲2,那麼咱們就得出了與你最相鄰的基友是B和A。

這就是與目標用戶最相鄰的K個用戶的計算。

經過這K個用戶來推薦商品了

好了,你的好基友咱們也算出來了,接下來要向你推薦商品了。可是咱們可推薦的商品有小米盒子,note2,蠟燭,潤膚霜,肥皂這麼四種,到底哪一種纔是你須要的呢?這裏的算法就比較普遍了,咱們能夠不排序,都一股腦推薦給你,但這明顯可能有些你不怎麼感興趣,咱們也能夠作一些處理,假如咱們算出來A和你的類似度是25%,B和你的類似度是80%,那麼對於上面這些產品,咱們的推薦度能夠這麼來算

  • 小米盒子: 1*0.25 = 0.25
  • note2: 1*0.25 = 0.25
  • 蠟燭: 1*0.25 = 0.25
  • 潤膚霜: 1*0.8 = 0.8
  • 肥皂: 10.8+10.25=1.05

這樣就一目瞭然了,很明顯,咱們會首先把肥皂推薦給你,這個多是你最須要的,其次是潤膚霜,而後纔是蠟燭,小米盒子和note2。

固然,你能夠把上述結果歸一化或者用其餘你以爲合適的方式來計算推薦度,無論怎麼算,推薦度仍是得和基友與你類似度有關係,就是那個0.8和0.25必定要用上,否則前面白算了。

算法總結

好了,經過這個例子,你大概知道了爲何會推薦肥皂給你了吧,這就是基於用戶的協同推薦算法的描述,總結起來就是這麼幾步

  1. 計算其餘用戶和你的類似度,可使用反差表忽略一部分用戶
  2. 根據類似度的高低找出K個與你最類似的鄰居
  3. 在這些鄰居喜歡的物品中,根據鄰居與你的遠近程度算出每一件物品的推薦度
  4. 根據每一件物品的推薦度高低給你推薦物品。

好比上面那個例子,首先,咱們經過反查表忽略掉了C女神,而後計算出A和B,D與你的類似度,而後根據K=2找出最類似的鄰居A和B,接着根據A,B與你類似度計算出每件物品的推薦度並排序,最後根據排好序的推薦度給你推薦商品。

怎麼樣,是否是很簡單啊。

算法存在的問題

這個算法實現起來也比較簡單,可是在實際應用中有時候也會有問題的。

好比一些很是流行的商品可能不少人都喜歡,這種商品推薦給你就沒什麼意義了,因此計算的時候須要對這種商品加一個權重或者把這種商品徹底去掉也行。

再有,對於一些通用的東西,好比買書的時候的工具書,如現代漢語詞典,新華字典神馬的,通用性太強了,推薦也沒什麼必要了。

這些都是推薦系統的髒數據,如何去掉髒數據,這是數據預處理的時候事情了,這裏就很少說了。

來個實戰的吧

說了這麼多,肥皂也推薦了,那麼咱們來點實際的,我這裏下載了movieLens的數據集,至於這個集合是什麼你們google一下,反正不少地方用來作測試算法的數據,這個數據集裏面有不少用戶對於電影的打分,咱們的需求是隨便輸入一個用戶,而後根據協同算法,給他推薦一些個電影。

因爲用戶給電影打分有好有壞[1到5分],而咱們上面的例子中都是說的喜歡某件物品而沒有說不喜歡的狀況,因此首先,咱們要把數據處理一下,簡單的來作,咱們能夠認爲3分以上的話表明這個用戶喜歡這個電影,不然就是不喜歡,這樣顯得有點太死板了,咱們也能夠這麼來定義,好比用戶A對30部電影打分了,首先求出他打分的平均值,而後高於這個平均值的咱們以爲用戶喜歡這個電影,不然認爲他不喜歡。

好了,用戶的喜歡與不喜歡的問題解決了。下面就能夠開始算法了,代碼不全貼出來了,貼個流程吧,具體代碼能夠去看個人github

#讀取文件數據
test_contents=readFile(file_name)
#文件數據格式化成二維數組 List[[用戶id,電影id,電影評分]...] 
test_rates=getRatingInformation(test_contents)  
#格式化成字典數據 
#    1.用戶字典:dic[用戶id]=[(電影id,電影評分)...]
#    2.電影用戶反查表:dic[電影id]=[用戶id1,用戶id2...]
test_dic,test_item_to_user=createUserRankDic(test_rates)
#尋找鄰居   
neighbors=calcNearestNeighbor(userid,test_dic,test_item_to_user)[:k]
#計算推薦列表 
recommend_dic={}
for neighbor in neighbors:
    neighbor_user_id=neighbor[1]
    movies=test_dic[neighbor_user_id]
    for movie in movies:
        if movie[0] not in recommend_dic:
            recommend_dic[movie[0]]=neighbor[0]
        else:
            recommend_dic[movie[0]]+=neighbor[0]
#創建推薦列表
recommend_list=[]
for key in recommend_dic:
    recommend_list.append([recommend_dic[key],key]
recommend_list.sort(reverse=True)複製代碼

對於隨便輸入一個用戶,咱們獲得如下這個推薦結果

movie name                release     
=======================================================
Contact (1997)                11-Jul-1997               
Scream (1996)                 20-Dec-1996               
Liar Liar (1997)              21-Mar-1997               
Saint, The (1997)             14-Mar-1997               
English Patient, The (1996)   15-Nov-1996               
Titanic (1997)                01-Jan-1997               
Air Force One (1997)          01-Jan-1997               
Star Wars (1977)              01-Jan-1977               
Conspiracy Theory (1997)      08-Aug-1997               
Toy Story (1995)              01-Jan-1995               
Fargo (1996)                  14-Feb-1997複製代碼

多輸入幾個用戶你就會發現,像Titanic,Star Wars這種超級熱門的電影,只要你選的這個用戶沒看過,推薦系統就必定會推薦給你,這就是咱們前面說的髒數據,實際系統中這種數據是須要處理掉得。咱們這篇文章只作算法講解,就不去管這些東西了。

最後,歡迎關注個人公衆號,不少東西會在那裏發出來。搜索XJJ267或者西加加語言便可

相關文章
相關標籤/搜索