聲明:以下是學習《集體編程智慧》的筆記普舆,代碼使用python編寫恬口。
需要有python自定義函數(shù)的知識,以及事先了解皮爾森相關系數(shù)的公式
網(wǎng)上總是有人吐槽:“XX的算法很可笑奔害,老是給我推薦我不想要的東西”楷兽。作為非計算機專業(yè)的普通人,一直不太明白何謂“算法”华临。比如豆瓣是怎么給我推薦我喜歡的電影的。就目前我的理解端考,就是通過某些數(shù)學公式雅潭,把我的興趣跟別人的興趣作比較,得出一個關聯(lián)度却特。而書中講述了如何用代碼實現(xiàn)扶供。
一個例子
書中給到一個很簡單的例子,大概是說每個用戶裂明,對每部電影的評分椿浓,構成一個字典,即由“用戶——電影名——評分”構成的字典闽晦。
critics={'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 3.5},
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
'The Night Listener': 4.5, 'Superman Returns': 4.0,
'You, Me and Dupree': 2.5},
'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 2.0},
'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane':4.5,'You, Me and Dupree':1.0,'Superman Returns':4.0}}
所以我們對其建立一個名為recommendations.py的文件扳碍,執(zhí)行:
from recommendations import critics
critics['Lisa Rose']['Lady in the Water']
就會得到2.5的結果。(跟翻字典一樣仙蛉,找到聲母笋敞、韻母就會得出對應的字)
如何考察兩個人的口味?這里就要把文字描述落地到圖表了:
尋找相近的用戶1——歐幾里得距離評價
上圖簡單展示了如何判斷兩個人的相似度——Toby和LaSalle的相似度就比和Seymour的相似度更大(坐標距離可見)荠瘪,計算距離我們用各自橫豎坐標差值平方和的開方(好拗口)表示:
from math import sqrt
sqrt(pow(4.5-4,2)+pow(1-2,2))
結果為1.118033988749895
當然夯巷,數(shù)字越小,距離越近哀墓,相關度越大趁餐。
但為了好記憶,我們希望數(shù)字越大篮绰,相關度越大后雷,就這么處理:
1/(1+sqrt(pow(4.5-4,2)+pow(1-2,2)))
分母加1是為了避免距離為零的時候出現(xiàn)錯誤。
尋找相近的用戶2——皮爾森相關度評價
(此段需要皮爾森相關函數(shù)的知識)
原因:皮爾森相關度評價的出現(xiàn)是源于對數(shù)據(jù)不規(guī)范時的考慮——如果影評者對影片的評論總是相對于平均水平偏離很大時(比如苛刻的影評者普遍給低分)——依然能給出合理的相關度評論阶牍。
方法:判斷兩組數(shù)據(jù)與某一直線的擬合程度
注意:皮爾森相關度是基于對物品距離的計算
上圖是相關度不盡相同的情況喷面,而下圖是相關度趨于一致的情況
這里Jack總是傾向比Lisa給出更高分值,但不影響我們判斷他倆有相似偏好(因為他們有趨同性)
在recommendations.py文件下def sim_pearson走孽,用于 判斷倆人的相似度
def sim_distance(prefs,person1,person2):
# 得到shared_items的列表
si={}
for item in prefs[person1]:
if item in prefs[person2]: si[item]=1
# 如果兩者沒有共同之處惧辈,則返回0
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+sum_of_squares)
執(zhí)行
print recommendations.sim_pearson(recommendations.critics,'Lisa Rose','Gene Seymour')
得到0.396059017191
推薦相似的人
而我們日常更常出現(xiàn)的需求是:知道一個人的愛好,向其推薦有共同喜好的人或可能會喜好的物磕瓷。
在recommendations.py文件下def topMatches盒齿,用于給待推薦的人打分
# 從反映偏好的字典中返回最為匹配者
# 返回結果的個數(shù)和相似度函數(shù)均為可選參數(shù)
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]
# 利用所有他人評價值的加權平均念逞,為某人提供建議
# of every other user's rankings
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
# 建立規(guī)范化列表
rankings=[(total/simSums[item],item) for item,total in totals.items()]
# 返回經(jīng)過排序的列表
rankings.sort()
rankings.reverse()
return rankings
這里,以找出跟Toby最接近的三個人為例:
import recommendations
recommendations.topMatches(recommendations.critics,'Toby',n=3)
得出
(0.9244734516419049, 'Mick LaSalle'),
(0.8934051474415647, 'Claudia Puig')]```
***
####推薦物品
書中用了一個表格來展示這個過程:
![python4.png](http://upload-images.jianshu.io/upload_images/1638110-379fdac8b939bcab.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
比如要為Toby推薦電影边翁,得從他沒看過的電影里找翎承,對這些沒看過的電影,用歐幾里得距離得出其他人跟Toby的相似度(加權)符匾,分別乘以他們對這些電影的評價叨咖,得出電影的得分(S.x列),再進行加總啊胶。
然而有個情況是某個人沒看過某電影甸各,(如Puig沒看過Lady),那Lady的總評分不是相對少了嗎焰坪。
所以我們還要做一個動作是:用總計除以有評論的人的相似度之和(Sim.Sum)(相當于減權)趣倾,就會得到相對公正的結果。
在recommendations.py文件下是這么實現(xiàn)的
利用所有他人評價值的加權平均某饰,為某人提供建議
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
建立規(guī)范化列表
rankings=[(total/simSums[item],item) for item,total in totals.items()]
返回經(jīng)過排序的列表
rankings.sort()
rankings.reverse()
return rankings
執(zhí)行
recommendations.getRecommendations(recommendations.critics,'Toby')
得到
```[(3.3477895267131013, 'The Night Listener'),
(2.8325499182641614, 'Lady in the Water'),
(2.5309807037655645, 'Just My Luck')]```
嗯儒恋,Toby可能更喜歡'The Night Listener'
以上是基于“人”的推薦,如果我們想知道哪些商品有相似性呢黔漂?
***
####相似商品推薦
只需將人和物進行對調:
把```{'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 3.5}} ```
變成```{'Lady in the Water':{'Lisa Rose':2.5,'Gene Seymour':3.0}, 'Snakes on a Plane':{'Lisa Rose':3.5,'Gene Seymour': 3.5} etc}```
在recommendations.py文件下
def transformPrefs(prefs):
result={}
for person in prefs:
for item in prefs[person]:
result.setdefault(item,{})
# 將物品和人員對調
result[item][person]=prefs[person][item]
return result
試試:
movies=recommendations.transformPrefs(recommendations.critics)
recommendations.topMatches(movies,'Superman Returns')
得到:
```[(0.6579516949597695, 'You, Me and Dupree'),
(0.4879500364742689, 'Lady in the Water'),
(0.11180339887498941, 'Snakes on a Plane'),
(-0.1798471947990544, 'The Night Listener'),
(-0.42289003161103106, 'Just My Luck')]```
也可以基于電影得出“喜歡它的人”
recommendations.getRecommendations(movies,'Just My Luck')
```[(4.0, 'Michael Phillips'), (3.0, 'Jack Matthews')]```
>學到哪兒诫尽,寫到哪兒。暫告一段落瘟仿。
>本人最近在求職箱锐,坐標北京,數(shù)據(jù)分析相關劳较,行業(yè)不限驹止,希望看到的簡友幫忙推薦,當然也希望HR能看到
.