提供推薦(集體智慧) —— 使用MovieLens數(shù)據(jù)為用戶推薦電影(Python)

0x00 下載MovieLens數(shù)據(jù)

1) 從網(wǎng)站http://grouplens.org/datasets/movielens/下載數(shù)據(jù)
2) u.item文件包含兩列數(shù)據(jù)旨怠,為電影id和電影名稱的對應(yīng)關(guān)系;u.data文件包含四列數(shù)據(jù)缔莲,為用戶id篮绰,電影id,評價(jià),時(shí)間

2016-07-20 21:25:24 的屏幕截圖.png

3)讀入數(shù)據(jù)
<code>

movie_list = {} #id:title
with open("./u.item") as f:
    for line in f.readlines():
        (mid, title) = line.split('|')[0:2]
        movie_list[mid] = title
pref_by_people = {}
with open("./u.data") as f:
    for line in f.readlines():
        (uid, mid, rating) = line.split('\t')[0:3]
        if not uid in pref_by_people.keys():
            pref_by_people[uid] = {}
        pref_by_people[uid][movie_list[mid]] = int(rating)

</code>
4)數(shù)據(jù)類型轉(zhuǎn)換 {people:{movie:1}} -->> {movie:{people:1}}
<code>

def TransfromPref(pref):
    re_pref = {}
    for k1, v1 in pref.items():
        for k2, v2 in v1.items():
            if not k2 in re_pref.keys():
                re_pref[k2] = {}
            re_pref[k2][k1] = v2
    return re_pref

pref_by_movie = TransfromPref(pref_by_people)

0x01 協(xié)同過濾兩種方式

協(xié)同過濾:常常被用于分辨某位特定顧客可能感興趣的東西扶欣,這些結(jié)論來自于對其他相似顧客對哪些產(chǎn)品感興趣的分析。

歐幾里德距離評價(jià)

1)以人們對事物的評價(jià)作為坐標(biāo)軸,比較兩人在坐標(biāo)空間的距離料祠,來判斷人們偏好的相近程度
2)代碼
<code>

def edclidean(prefs, person1, person2):
    #找出兩人均做出評價(jià)的事物
    both_list = [item for item in prefs[person1].keys() if item in prefs[person2].keys()] 
    #計(jì)算距離
    dis = math.sqrt(sum([(prefs[person1][item] - perfs[person2][item]) ** 2 for item in both_list])) 
    #以距離的倒數(shù)為返回值骆捧,兩人偏好程度越就近,該值越大髓绽,假設(shè)不存在完全相同的兩人敛苇,不考慮dis為0的情況
    return 1/dis 

</code>
prefs中以python字典嵌套字典的方式存儲了每個(gè)人對于某時(shí)候的評價(jià)
prefs = {person:{item:1...}...},下同

皮爾遜相關(guān)系數(shù)評價(jià)

1)考慮到人們對于事物的評價(jià)標(biāo)準(zhǔn)不同顺呕,即有些人傾向打出更高的分?jǐn)?shù)枫攀,而其他人更傾向于打出較低的分?jǐn)?shù)诫欠,這是單純的考慮邏輯空間距離就不能很好的得出相近的偏好程度(例:person1對item1和item2打分分別為6和8妇斤,person2對item1和item2打分分別為8和10好爬,兩人分?jǐn)?shù)不相同腋逆,但兩人的評價(jià)有相同的趨勢咐蚯,此時(shí)也認(rèn)為兩人偏好相同)
2)皮爾遜相關(guān)系數(shù)計(jì)算

2016-07-20 20:04:24 的屏幕截圖.png

3)代碼
<code>
通過每個(gè)電影人們的評價(jià)計(jì)算出電影之間的相關(guān)系數(shù)瘩例,將上例中通過中每個(gè)人對電影的評價(jià)計(jì)算人們之間的相關(guān)系數(shù)同理

def Pearson(pref , movie1, movie2):
#找出對兩部電影都評論的人
    people_list = [person for person in pref[movie1].keys() if person in pref[movie2].keys()]
    n = len(people_list)
    if n == 0:
        return 0
    #計(jì)算評價(jià)和
    sum1 = sum([pref[movie1][person] for person in people_list])
    sum2 = sum([pref[movie2][person] for person in people_list])
    #計(jì)算評價(jià)平方和
    sumSq1 = sum([pref[movie1][person] ** 2 for person in people_list])
    sumSq2 = sum([pref[movie2][person] ** 2 for person in people_list])
    #計(jì)算評價(jià)成績和
    psum = sum([pref[movie1][person] * pref[movie2][person] for person in people_list])
    # 皮爾遜相關(guān)系數(shù)計(jì)算
    num = psum - sum1 * sum2 / n
    den = sqrt((sumSq1 - (sum1 ** 2) / n) * (sumSq2 - (sum2 ** 2) / n))

    if den == 0:
        return 0
    return num / den

</code>

0x02 根據(jù)電影推薦相關(guān)的電影

1)通過皮爾遜相關(guān)系數(shù)計(jì)算出每個(gè)電影的最相近的電影
<code>

def TopMatch(pref, movie, n = 5):
    #計(jì)算給電影和每部電影的皮爾遜相關(guān)系數(shù)
    scores = [(Pearson(pref_by_movie, movie, mov), mov) for mov in pref_by_movie.keys() if mov != movie]
    #根據(jù)系數(shù)進(jìn)行排序惋戏,并由大到小排序
    scores.sort(key = lambda x:x[0], reverse = True)
    return scores[0:n]

</code>
2)對每部電影計(jì)算最接近電影炮捧,得到match_list
<code>

def CreateMatchList(pref = pref_by_movie):
    match_list = {}
    for movie in pref.keys():
        match_list[movie] = TopMatch(pref, movie, 5)
    return match_list

match_list = CreateMatchList()

</code>

0x03 為用戶推薦電影

1)找到我們已經(jīng)看過的電影和評價(jià)驰徊,從match_list中找出那些和我們看過的影片相近程度更高的沒看過的電影笤闯,用相關(guān)系數(shù)作為權(quán)值,計(jì)算每部電影的評分的加權(quán)平均值棍厂。

2016-07-20 20:41:09 的屏幕截圖.png

例:每一橫列出我們看過的電影第一列是我們對它的評分颗味,之后的沒兩列分別是新電影的相關(guān)系數(shù)和系數(shù)乘評分的值,總計(jì)記錄的相關(guān)系數(shù)的和與相關(guān)系數(shù)與評分的乘機(jī)的和牺弹,最后一橫做除法得到評分的加權(quán)平均數(shù)浦马,即推薦得分,分?jǐn)?shù)越高的越值得推薦
2)代碼
<code>

def get_recommanded_items(pref = pref_by_people, match_list = match_list, user = '1'):
    try:
        user_ratings = pref[user] #找出用戶看過的電影與評價(jià)
    except KeyError:
        print("no user")
        return 0
    scores = {} #記錄加權(quán)和
    totalsim = {} #記錄評分和

    for movie, rating in user_ratings.items(): #遍歷當(dāng)前用戶評分電影
        for sim, sim_movie in match_list[movie]: #遍歷當(dāng)前電影相近電影
            if sim_movie in user_ratings.keys(): #如果用戶看過該電影张漂,跳出本次循環(huán)
                continue
             #記錄加權(quán)和與評分和
            if not sim_movie in scores.keys():
                scores[sim_movie] = sim * rating
                totalsim[sim_movie] = sim 
            scores[sim_movie] += sim * rating
            totalsim[sim_movie] += sim

    rankings = [(scores[sim_movie]/totalsim[sim_movie], sim_movie) for sim_movie in scores.keys() if totalsim[sim_movie] != 0]
    #排序并取前5
    rankings.sort(key=lambda x:x[0], reverse=True)
    return rankings[0:5]

</code>

0x04 基于用戶進(jìn)行過濾還是基于物品進(jìn)行過濾

1)本文采用了基于物品方式的過濾晶默,即對每樣物品計(jì)算和它相似的物品。當(dāng)為某位用戶推薦時(shí)航攒,我們找到他過去評分靠前的物品磺陡,再找出這些物品相似的物品,用相關(guān)系數(shù)作為權(quán)值漠畜,計(jì)算每個(gè)物品的評分的加權(quán)平均值
2)基于用戶的推薦即對每位用戶求出和他取向相近的人币他,找出這些人中評分靠前的物品,用相關(guān)系數(shù)作為權(quán)值憔狞,計(jì)算每個(gè)物品的評分的加權(quán)平均值
3)物品間相似度的變化不會(huì)向人之間變化那么快蝴悉,即相關(guān)系數(shù)計(jì)算不用那么頻繁,可以事先計(jì)算好瘾敢,不用在每次推薦時(shí)都計(jì)算
4)針對大量數(shù)據(jù)推薦列表時(shí)拍冠,基于物品的過濾明顯比基于用戶的過濾快硝枉,不過需要額外的存儲空間開銷。
5)對于稀疏數(shù)據(jù)集倦微,基于物品的推薦明顯優(yōu)于基于用戶的推薦妻味;對于密集數(shù)據(jù)集,兩者效果類似

0x05 測試

2016-07-20 21:11:26 的屏幕截圖.png

輸入用戶id得到推薦電影的前5位
第一次推薦由于需要計(jì)算match_list欣福,花費(fèi)較長時(shí)間

代碼下載:鏈接: http://pan.baidu.com/s/1jILdXtk 密碼: xyzd
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末责球,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子拓劝,更是在濱河造成了極大的恐慌雏逾,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件郑临,死亡現(xiàn)場離奇詭異栖博,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)厢洞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門仇让,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人躺翻,你說我怎么就攤上這事丧叽。” “怎么了公你?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵踊淳,是天一觀的道長。 經(jīng)常有香客問我陕靠,道長迂尝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任剪芥,我火速辦了婚禮垄开,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘粗俱。我一直安慰自己说榆,他們只是感情好虚吟,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布寸认。 她就那樣靜靜地躺著,像睡著了一般串慰。 火紅的嫁衣襯著肌膚如雪偏塞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天邦鲫,我揣著相機(jī)與錄音灸叼,去河邊找鬼神汹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛古今,可吹牛的內(nèi)容都是我干的屁魏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捉腥,長吁一口氣:“原來是場噩夢啊……” “哼氓拼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起抵碟,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤桃漾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拟逮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撬统,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年敦迄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恋追。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡罚屋,死狀恐怖几于,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沿后,我是刑警寧澤沿彭,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站尖滚,受9級特大地震影響喉刘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜漆弄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一睦裳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撼唾,春花似錦廉邑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至渤愁,卻和暖如春牵祟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背抖格。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工诺苹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留咕晋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓收奔,卻偏偏與公主長得像掌呜,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子坪哄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容