提供推荐(集体智慧) —— 使用MovieLens数据为用户推荐电影(Python)

0x00 下载MovieLens数据

1) 从网站http://grouplens.org/datasets/movielens/下载数据
2) u.item文件包含两列数据,为电影id和电影名称的对应关系;u.data文件包含四列数据,为用户id,电影id,评价,时间

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

3)读入数据
<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)数据类型转换 {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 协同过滤两种方式

协同过滤:常常被用于分辨某位特定顾客可能感兴趣的东西,这些结论来自于对其他相似顾客对哪些产品感兴趣的分析。

欧几里德距离评价

1)以人们对事物的评价作为坐标轴,比较两人在坐标空间的距离,来判断人们偏好的相近程度
2)代码
<code>

def edclidean(prefs, person1, person2):
    #找出两人均做出评价的事物
    both_list = [item for item in prefs[person1].keys() if item in prefs[person2].keys()] 
    #计算距离
    dis = math.sqrt(sum([(prefs[person1][item] - perfs[person2][item]) ** 2 for item in both_list])) 
    #以距离的倒数为返回值,两人偏好程度越就近,该值越大,假设不存在完全相同的两人,不考虑dis为0的情况
    return 1/dis 

</code>
prefs中以python字典嵌套字典的方式存储了每个人对于某时候的评价
prefs = {person:{item:1...}...},下同

皮尔逊相关系数评价

1)考虑到人们对于事物的评价标准不同,即有些人倾向打出更高的分数,而其他人更倾向于打出较低的分数,这是单纯的考虑逻辑空间距离就不能很好的得出相近的偏好程度(例:person1对item1和item2打分分别为6和8,person2对item1和item2打分分别为8和10,两人分数不相同,但两人的评价有相同的趋势,此时也认为两人偏好相同)
2)皮尔逊相关系数计算

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

3)代码
<code>
通过每个电影人们的评价计算出电影之间的相关系数,将上例中通过中每个人对电影的评价计算人们之间的相关系数同理

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
    #计算评价和
    sum1 = sum([pref[movie1][person] for person in people_list])
    sum2 = sum([pref[movie2][person] for person in people_list])
    #计算评价平方和
    sumSq1 = sum([pref[movie1][person] ** 2 for person in people_list])
    sumSq2 = sum([pref[movie2][person] ** 2 for person in people_list])
    #计算评价成绩和
    psum = sum([pref[movie1][person] * pref[movie2][person] for person in people_list])
    # 皮尔逊相关系数计算
    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 根据电影推荐相关的电影

1)通过皮尔逊相关系数计算出每个电影的最相近的电影
<code>

def TopMatch(pref, movie, n = 5):
    #计算给电影和每部电影的皮尔逊相关系数
    scores = [(Pearson(pref_by_movie, movie, mov), mov) for mov in pref_by_movie.keys() if mov != movie]
    #根据系数进行排序,并由大到小排序
    scores.sort(key = lambda x:x[0], reverse = True)
    return scores[0:n]

</code>
2)对每部电影计算最接近电影,得到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)找到我们已经看过的电影和评价,从match_list中找出那些和我们看过的影片相近程度更高的没看过的电影,用相关系数作为权值,计算每部电影的评分的加权平均值。

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

例:每一横列出我们看过的电影第一列是我们对它的评分,之后的没两列分别是新电影的相关系数和系数乘评分的值,总计记录的相关系数的和与相关系数与评分的乘机的和,最后一横做除法得到评分的加权平均数,即推荐得分,分数越高的越值得推荐
2)代码
<code>

def get_recommanded_items(pref = pref_by_people, match_list = match_list, user = '1'):
    try:
        user_ratings = pref[user] #找出用户看过的电影与评价
    except KeyError:
        print("no user")
        return 0
    scores = {} #记录加权和
    totalsim = {} #记录评分和

    for movie, rating in user_ratings.items(): #遍历当前用户评分电影
        for sim, sim_movie in match_list[movie]: #遍历当前电影相近电影
            if sim_movie in user_ratings.keys(): #如果用户看过该电影,跳出本次循环
                continue
             #记录加权和与评分和
            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 基于用户进行过滤还是基于物品进行过滤

1)本文采用了基于物品方式的过滤,即对每样物品计算和它相似的物品。当为某位用户推荐时,我们找到他过去评分靠前的物品,再找出这些物品相似的物品,用相关系数作为权值,计算每个物品的评分的加权平均值
2)基于用户的推荐即对每位用户求出和他取向相近的人,找出这些人中评分靠前的物品,用相关系数作为权值,计算每个物品的评分的加权平均值
3)物品间相似度的变化不会向人之间变化那么快,即相关系数计算不用那么频繁,可以事先计算好,不用在每次推荐时都计算
4)针对大量数据推荐列表时,基于物品的过滤明显比基于用户的过滤快,不过需要额外的存储空间开销。
5)对于稀疏数据集,基于物品的推荐明显优于基于用户的推荐;对于密集数据集,两者效果类似

0x05 测试

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

输入用户id得到推荐电影的前5位
第一次推荐由于需要计算match_list,花费较长时间

代码下载:链接: http://pan.baidu.com/s/1jILdXtk 密码: xyzd
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容