写点什么

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

  • 2015-05-07
  • 本文字数:1997 字

    阅读完需:约 7 分钟

时至今日,虽然海量数据、大数据、数据挖掘、个性化等名词术语已耳熟能详,仿佛谁人两两遇到都可以轻易写个挖掘系统出来,但情况真的是这样么? Flipboard 数据产品部门的工程师 Ben Frederickson 在与友人的讨论中就发现,写个推荐系统并没有那么轻而易举,为此他专门写了一篇博文来记录自己实现的整个过程,利用的工具是数据挖掘领域很热门的 Pandas SciPy 函数库,最后使用 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 读者交流群)。

2015-05-07 08:095008
用户头像

发布了 268 篇内容, 共 138.6 次阅读, 收获喜欢 24 次。

关注

评论

发布
暂无评论
发现更多内容

Flink初体验

数据社

大数据 flink 流计算

【gRPC】Python调用Java的gRPC服务

遇见

Java Python gRPC

写一个开源的 macOS 程序可以赚多少钱?

子骅 luin

node.js redis GitHub 开源 赚钱

人们喜欢彼此制造困难让大家难过

Fenng

用声音在一起,听荔枝CTO丁宁聊UGC声音互动平台的技术世界

ONES 王颖奇

内容 企业架构 互联网

此为开卷

X.F

毕竟,一生很短,少有圆满

霍太稳@极客邦科技

创业 身心健康 个人成长

翻译: Effective Go (1)

申屠鹏会

翻译 Go 语言

电子书:《Linux Perf Master》

RiboseYim

Linux 性能优化

WebSphere Application Server运维实践 --从入门到监控

rafe

Java WAS perfservlet visualVM JMX

为什么你的创业公司应该运行在Kubernetes上

云原生

云原生 k8s

一文讲清楚 MySQL 事务隔离级别和实现原理,开发人员必备知识点

古时的风筝

MySQL 数据库 事务隔离级别 mysql事务 数据库事务

uni-app黑魔法:小程序自定义组件运行到H5平台

崔红保

小程序 uni-app

芋道 Spring Cloud Alibaba 介绍

艿艿

阿里巴巴 分布式 微服务 Spring Cloud Spring Boot

【Vue3.0 Beta】尝鲜

德育处主任

CSS Java html5 Vue 大前端

浅谈汽车行业嵌入式软件发布的流程有多复杂

WB

程序员 软件

初入响应式编程(上)

CD826

spring 微服务 Spring Cloud 响应式编程 reactor

对话 CTO〡和 PingCAP CTO 黄东旭聊开源数据库新蓝海

ONES 王颖奇

数据库 分布式 开发者

【数据结构】双向链表插入操作的时间复杂度分析

遇见

数据结构 算法 时间复杂度

2020了,各家小程序发展的怎么样?

崔红保

小程序 uni-app

分享多年积累的 macOS 效率工具

张晓辉

macos

业务代码必须要做的事情

程序员劝退师

Linux 性能诊断:负载评估入门

RiboseYim

Linux 性能优化

OKR实践中的痛点(1):老板的KR我的O,怎么办?

大叔杨

OKR Scrum 敏捷

业务系统开发程序员常用linux知识

程序员劝退师

Linux

寻找伴侣最重要的是什么?

二爷

一个创业者的途中思考

非著名程序员

创业 读书笔记 程序员 重新理解创业 思考

测试

Chonge

近两年影响我的两个重要原则

Selina

从流程、认知上做稳定的系统演进

Skysper

系统设计 质量管理

走出舒适区最好办法别走了,扩大它

乐少

歌曲推荐系统实践:Pandas、SciPy和D3.js_语言 & 开发_张天雷_InfoQ精选文章