BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

歌曲推荐系统实践:Pandas、SciPy和D3.js

| 作者 张天雷 关注 4 他的粉丝 发布于 2015年5月8日. 估计阅读时间: 7 分钟 | GMTC大前端的下一站,PWA、Web框架、Node等最新最热的大前端话题邀你一起共同探讨。

时至今日,虽然海量数据、大数据、数据挖掘、个性化等名词术语已耳熟能详,仿佛谁人两两遇到都可以轻易写个挖掘系统出来,但情况真的是这样么? Flipboard数据产品部门的工程师Ben Frederickson在与友人的讨论中就发现,写个推荐系统并没有那么轻而易举,为此他专门写了一篇博文来记录自己实现的整个过程,利用的工具是数据挖掘领域很热门的PandasSciPy函数库,最后使用D3.js进行交互和可视化,相关的代码都放在了GitHub上。

具体来讲,一个推荐系统包括数据的获取和存储,相似度的计算以及最终结果的可视化,下面分别阐述。

数据获取

Ben的推荐系统是针对Last.fm用户的,所用数据集是通过Last.fm的API获取的大约36万用户对歌手的喜爱程度。程度以用户对该歌手的播放次数为指标,数据集大小在1千7百万左右。想要在程序中使用这个数据集,ben通过Python数据挖掘工具Pandas的read_table将csv格式的数据导入成为表格。

data = pandas.read_table("usersha1-artmbid-artname-plays.tsv", 
                         usecols=[0, 2, 3], 
                         names=['user', 'artist', 'plays'])

将数据加载为表格以后,剩下的任务就是计算相似度了,ben给出了三种相似度的计算方法,分别是简单的相似度计算,余弦相似度和来自信息学的相似度计算,并给出了各类方法最后的可视化比较。

简单相似度

简单相似度计算,顾名思义,是最简单的相似度计算方法,用来计算两个歌手的相似程度。这种计算方法,忽略歌手被用户播放的次数,只是简单计算两个歌手重叠的用户数目。

def overlap(a, b):
    return len(a.intersection(b))

这种计算方法的问题在于,那些流行的歌手的存在,会极大影响相似度的准确性。例如几乎每个用户都听过Radiohead、Coldplay和披头士,这使得简单相似度方法给出的答案里面,越是流行的歌手越相似。

为了解决这个问题,ben引入了新的相似度定义,Jaccard相似度,利用数据挖掘中常用的正则化(Normalize)手段,将简单相似度正则化,消除用户数目对歌手相似度的影响,具体计算方法如下:

def jaccard(a, b):
    intersection = float(len(a.intersection(b)))
    return intersection / (len(a) + len(b) - intersection)

类似的正则化方法还有很多,比如Dice正则和Ochiai正则等,从一定程度上改善了相似度计算的准确性,但也带来了一点问题,即集合大小相近的歌手会更加相似,ben觉得这样也并不合理,因此进一步提出了使用余弦相似度。

余弦相似度

上文中提到的简单相似度抛弃了用户对歌手播放次数这一重要信息,实际上它代表了用户对该歌手的喜爱程度,细想一下是非常有道理的,一个披头士的重度听众怎么能够跟听过寥寥几曲的听众一样呢?那么,利用上播放次数这一信息最直接的办法,就是余弦相似度方法,计算公式如下:

def cosine(a, b):
    return dot(a, b.T)[0, 0] / (norm2(a) * norm2(b))

通过上面公式,我们就可以将播放次数引入到相似度的计算中。公式中的a和b分别代表歌手的听众向量,通过下面的代码构造生成:

# map each username to a unique numeric value
userids = defaultdict(lambda: len(userids))
data['userid'] = data['user'].map(userids.__getitem__)

# map each artist to a sparse vector of their users
artists = dict((artist, csr_matrix(
                (group['plays'], (zeros(len(group)), group['userid'])),
                shape=[1, len(userids)]))
        for artist, group in data.groupby('artist'))

来自信息学的相似度

除了单纯利用播放次数以外,ben还介绍了来自信息学的,确切来讲是来自搜索引擎中常用的自然语言处理技术,来计算歌手之间的相似度,即词频-逆文档频率(TF-IDF)作为向量的相似度计算方法。

这种相似度的发明,来自搜索引擎对检索结果排序的需求,即计算检索关键词与检索返回的文档之间的相似程度。具体来讲,如果某个词语在一个描述语句中出现的频率很高(TF很高),而在其他描述语句中很少出现(IDF很高),则认为该词语具有很好的区分文档的能力,其TF-IDF值就比较高,那么对应到歌曲推荐这个任务来讲,ben将用户(听众)看作一个个的单词,来进一步考虑特定用户对相似度准确性的影响,可谓是三种方法中比较准确的一个了,ben还在原文中用D3.js给出了几种相似度的效果对比分析。

总结

在专业术语充斥耳畔的今天,能够有耐心真正自己去尝试一些想当然的东西、算法甚至系统,是非常难能可贵的精神,而收获也是非常丰富的。Ben以Python中常用的Pandas和SciPy等工具,展现了从头实现一个推荐系统的方法,正是这种精神的实践典范。


感谢崔康对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入InfoQ读者交流群InfoQ好读者)。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

做的很一般吧 by henyo ma

数据量这么小,算法这么简单,可视化做的也很初级,骗钱的吧

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

1 讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT