集體智慧編程學習之推薦系統

來源:互聯網
上載者:User

打算從這篇開始,一邊學習一邊寫些資料採礦的東西,主要是督促自己學習和總結。

我最開始的網購是從china-pub買了一本《Unix/Linux編程實踐教程》,書好,便宜,並且可以貨到付款,很是吸引我這種懶窮學生,於是一發不可收拾買了很多書,後來轉戰dangdang,再後來就是amazon,現在基本都在jd買了,除了書,還會在yihaodian買一些日用品。後來發現這幾家都會有推薦,dangdang和china-pub的推薦沒什麼印象,jd的推薦離我的興趣點差的挺遠,印象深刻的就是amazon,有次推送的郵件真是推到我心坎坎了。這次我也來做一個木偶推薦系統玩玩。

好吧,今晚閑來無聊,想找本書來消遣。現在書籍甚是豐富,買哪本書呢?

1)我會打電話問問朋友,請求推薦;

2)還會登陸網站看暢銷top100,選一本自己感興趣的;

慢慢就會發現問題,第一:朋友推薦和top100的書籍比較穩定,新意不多,看完了想看新的就沒了,第二:這裡面很合自己脾氣的書不多,自己很厭倦太巨頭或太學府派的書,還有就是現在的top100很多孕育和養生的東東,目前我就先忍忍吧。

好了,既然目前都在說大資料,怎麼用大資料進行推薦呢?我首先想到的是,我喜歡《Unix/Linux編程實踐教程》,和這本內容寫作風格近似的也應該是我喜歡的,我喜歡packt出版社的一本書,可能這個出版社出版的其他書我也喜歡(事實也是我非常喜歡這個出版社的書),我喜歡《Think
in C++》,我可能還會喜歡bruce eckel出的其他書(事實也是這樣)。還有一種情況,我是碼農,我有個碼農朋友,我兩興趣愛好相投,他喜歡的書可能也是我喜歡的書,我喜歡的書也可能是他喜歡的書(事實也是這樣)。好,總結一下,第一種基於物品的推薦,我買了A,很可能會喜歡和A相似的B,第二種基於使用者推薦,我和C志趣相投,他喜歡D,我可能也喜歡D。

我們先來說說評價,最先想到的評價有兩種,買與不買(1和0);買了打幾顆星(通常滿星是五顆,0,1,2,3,4,5),還有容許打半顆星的,這樣就有(0,
0.5,1,1.5,2,2.5 。。。5)。下面我們用0--5之間的小數表示評價,值越打表示評價越高,比如,我喜歡A,我給他5星,一般喜歡B,我給他3.8星,我很討厭C,我給他0星;於是有了下面一個變數ctitics:

critics = {'user1': {'goods1': 2.5, 'goods2': 3.5, 'goods3': 3.0, 'goods4': 3.5, 'goods5': 2.5, 'goods6': 3.0},'user2': {'goods1': 3.0, 'goods2': 3.5, 'goods3': 1.5, 'goods4': 5.0, 'goods6': 3.0, 'goods5': 3.5}, 'user3': {'goods1': 2.5, 'goods2': 3.0, 'goods4': 3.5, 'goods6': 4.0},'user4': {'goods2': 3.5, 'goods3': 3.0, 'goods6': 4.5, 'goods4': 4.0, 'goods5': 2.5},'user5': {'goods1': 3.0, 'goods2': 4.0, 'goods3': 2.0, 'goods4': 3.0, 'goods6': 3.0, 'goods5': 2.0}, 'user6': {'goods1': 3.0, 'goods2': 4.0, 'goods6': 3.0, 'goods4': 5.0, 'goods5': 3.5},'user7': {'goods2': 4.5, 'goods5': 1.0, 'goods4': 4.0}}

下面來定義“相似”,“相似”就是在某些方面很接近,怎麼考量相似呢,對上面的變數ctitics,怎麼判斷user1和那個其他user*相似,然後給出推薦呢,首先想到的是歐幾裡得距離評價,這就是最簡單的求兩點距離的公式,

下面來計算任意兩個使用者之間的“相似性”:

from math import sqrtdef sim_distance(prefs,person1,person2):  si={}  for item in prefs[person1]:     if item in prefs[person2]: si[item]=1  if len(si)==0: return 0  sum_of_squares=sum([pow(prefs[person1][item]-prefs[person2][item],2)                       for item in prefs[person1] if item in prefs[person2]])  return 1/(1+sqrt(sum_of_squares))


注意最後一行,按照基本的歐幾裡得距離,兩個越相近的人距離值越小,通常我們的做法是近似度越大會給出越大的值,所以這個修正總會返回0-1之間的值,返回1表示兩人居右完全相同的愛好。

好吧,我們中總會有一些人很挑剔,總有一些人不那麼挑剔,這些挑剔的人總趨向於給出整體偏低的評價(3,2,1),有些不那麼挑剔的人總趨向與給出整體偏高的評價(5,4,3),但是這兩種人的整體偏好相似,都會給goods1一個在他們認為較高的星星數(3和5),都會給goods2一個在他們認為較差的星星數(1和3)。這種情況下,用歐幾裡得距離計算的結果就不那麼具有競爭力了,如何修正這種偏差呢?我們來看看皮爾遜相關度評價。


下面來計算使用者之間的皮爾遜相關度:

def sim_pearson(prefs,p1,p2):  si={}  for item in prefs[p1]:     if item in prefs[p2]: si[item]=1  if len(si)==0: return 0  n=len(si)    sum1=sum([prefs[p1][it] for it in si])  sum2=sum([prefs[p2][it] for it in si])    sum1Sq=sum([pow(prefs[p1][it],2) for it in si])  sum2Sq=sum([pow(prefs[p2][it],2) for it in si])     pSum=sum([prefs[p1][it]*prefs[p2][it] for it in si])    num=pSum-(sum1*sum2/n)  den=sqrt((sum1Sq-pow(sum1,2)/n)*(sum2Sq-pow(sum2,2)/n))  if den==0: return 0  r=num/den  return r


還有很多計算相似性的方式,等用到時再學習吧。


下面我們就可以判斷任意使用者的相似性了:

def topMatches(prefs,person,n=5,similarity=sim_pearson):  scores=[(similarity(prefs,person,other),other)                   for other in prefs if other!=person]  scores.sort()  scores.reverse()  return scores[0:n]

注意topMatches的最後一個參數是一個函數名,是我們上面說的計算相似性的任意一種方法,只要他們有相同的函數簽名即可,這樣我們可以隨時換用我們想用的相似性計算方式。
來看看在我機器上計算出來的效果吧:

>>> import test>>> test.topMatches(test.critics, 'user1')[(0.9912407071619299, 'user7'), (0.7470178808339965, 'user6'), (0.5940885257860044, 'user5'), (0.5669467095138396, 'user4'), (0.40451991747794525, 'user3')]>>> test.topMatches(test.critics, 'user2')[(0.963795681875635, 'user6'), (0.41176470588235276, 'user5'), (0.39605901719066977, 'user1'), (0.38124642583151164, 'user7'), (0.31497039417435607, 'user4')]>>> test.topMatches(test.critics, 'user3')[(1.0, 'user4'), (0.40451991747794525, 'user1'), (0.20459830184114206, 'user2'), (0.13483997249264842, 'user6'), (-0.2581988897471611, 'user5')]>>> test.topMatches(test.critics, 'user4')[(1.0, 'user3'), (0.8934051474415647, 'user7'), (0.5669467095138411, 'user5'), (0.5669467095138396, 'user1'), (0.31497039417435607, 'user2')]>>> test.topMatches(test.critics, 'user5')[(0.9244734516419049, 'user7'), (0.5940885257860044, 'user1'), (0.5669467095138411, 'user4'), (0.41176470588235276, 'user2'), (0.21128856368212925, 'user6')]>>> test.topMatches(test.critics, 'user6')[(0.963795681875635, 'user2'), (0.7470178808339965, 'user1'), (0.66284898035987, 'user7'), (0.21128856368212925, 'user5'), (0.13483997249264842, 'user3')]>>> test.topMatches(test.critics, 'user7')[(0.9912407071619299, 'user1'), (0.9244734516419049, 'user5'), (0.8934051474415647, 'user4'), (0.66284898035987, 'user6'), (0.38124642583151164, 'user2')]


好了,終於找到了臭味相投的同志,給出一個推薦呢?

(1)我們可以從志投道和的user中,找一個他評價很高而我們沒有看過的一個goods,

(2)我們在所有志同道合的user中,用相似性和評價的一個加權評價值來給googs打分,從而形成一個排名進而推薦。

很顯然,我們採用第二種,為此,我們需要取得其他評論者相似性後,再乘以評論者為每個goods的評價值,就會得到我們想要的排名。

這中間會有一個問題,就是如果一個goods的評論user很多,那麼最終排名會比較靠前,而較少評論的goods最最終的影響會比較小,通常這樣沒什麼問題,我們在這裡稍微做一些修正,就是用對這個goods評價的所有其他users的相似性之和除以最終的排名值,這樣會公平一些,哈哈哈,來看代碼:

def getRecommendations(prefs,person,similarity=sim_pearson):  totals={}  simSums={}  for other in prefs:    if other==person: continue    sim=similarity(prefs,person,other)    if sim<=0: continue    for item in prefs[other]:            if item not in prefs[person] or prefs[person][item]==0:        totals.setdefault(item,0)        totals[item]+=prefs[other][item]*sim        simSums.setdefault(item,0)        simSums[item]+=sim  rankings=[(total/simSums[item],item) for item,total in totals.items()]  rankings.sort()  rankings.reverse()  return rankings


下面,我們可以進行推薦啦,來看看我計算的結果。user1,user2,user5評價全了所有goods,所以給不出新推薦。

>>> import test>>> test.getRecommendations(test.critics, 'user1')[]>>> test.getRecommendations(test.critics, 'user2')[]>>> test.getRecommendations(test.critics, 'user3')[(2.8092760065251268, 'goods3'), (2.694636703980363, 'goods5')]>>> test.getRecommendations(test.critics, 'user4')[(2.683756272799255, 'goods1')]>>> test.getRecommendations(test.critics, 'user5')[]>>> test.getRecommendations(test.critics, 'user6')[(2.1505590044630245, 'goods3')]>>> test.getRecommendations(test.critics, 'user7')[(3.3477895267131013, 'goods6'), (2.832549918264162, 'goods1'), (2.5309807037655645, 'goods3')]



上面我們不僅計算出了相似性,還給出了推薦。值得一提的是,計算相似性不僅可以計算user之間的相似性,還可以計算goods之間的相似性,根據user已買的物品推薦相似性較高的物品在jd和amazon也很常見。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.