基于网易云音乐评论的用户推荐系统
Posted Python中文社区
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于网易云音乐评论的用户推荐系统相关的知识,希望对你有一定的参考价值。
伪文艺Boy,Python、R、Java爱好者,喜欢新鲜感,一个简单、纯粹的IT小伙。
博客:https://blog.csdn.net/striver6
番外篇:
一、文本相似计算原理
1.1 TF-IDF
我们在判断一个词的重要性的时候,不能仅仅依靠词频来处理,因此引入了TF-IDF值。TF-IDF是Term Frequency - Inverse Document Frequency的缩写,即“词频-逆文本频率”。它由两部分组成,TF和IDF。
TF是词频,我们后面做的词条—文档矩阵给出了文本中各个词的出现频率统计,并作为文本特征,这个很好理解。而IDF,即“逆文本频率”,则反映了一个词在所有文本中出现的频率,如果一个词在很多的文本中出现,那么它的IDF值应该低。反过来,如果一个词在比较少的文本中出现,那么它的IDF值应该高。比如一些专业的名词如“Machine Learning”。这样的词IDF值应该高。一个极端的情况,如果一个词在所有的文本中都出现,那么它的IDF值应该为0。
上面是从定性上说明的IDF的作用,那么如何对一个词的IDF进行定量分析呢?这里直接给出一个词x的IDF的基本公式如下:
IDF(x)=log(N/N(x))
(5.1)
其中,N代表语料库中文本的总数,而N(x)代表语料库中包含词x的文本总数。
当然,在一些特殊的情况IDF计算会有一些小问题,比如某一个生僻词在语料库中没有,这样我们的分母为0, IDF没有意义了。所以常用的IDF我们需要做一些平滑,使语料库中没有出现的词也可以得到一个合适的IDF值。平滑的方法有很多种,最常见的IDF平滑后的公式之一为:
IDF(x)=log((N+1)/(N(x)+1))+1
(5.2)
有了IDF的定义,我们就可以计算某一个词的TF-IDF值了:
TF−IDF(x)=TF(x)∗IDF(x)
(5.3)
其中TF(x)指词x在当前文本中的词频。
1.2 Doc2Bow模型
Word2vec和Doc2Bow同属两位学术大牛Quoc Le 和 Tomas Mikolov发明的。
在2014年的《Distributed Representations of Sentences and Documents》所提出文章向量(Documents vector),或者称句向量(Sentences vector),当然在文章中,统一称这种向量为Paragraph Vector。
Word2vec涉及到很多数学模型,囊括了词向量的理解、sigmoid函数、逻辑回归、Bayes公式、Huffman编码、n-gram模型、浅层神经网络、激活函数、最大似然及其梯度推导、随机梯度下降法、词向量与模型参数的更新公式、CBOW模型和 Skip-gram模型、Hierarchical Softmax算法和Negative Sampling算法等。当然还会结合google发布的C源码(好像才700+行),讲述相关部分的实现细节,比如Negative Sampling算法如何随机采样、参数更新的细节、sigmod的快速近似计算、词典的hash存储、低频与高频词的处理、窗口内的采样方式、自适应学习、参数初始化、w2v实际上含有两中方法等,用C代码仅仅700+行实现,并加入了诸多技巧。
1.3 计算相似度
本文使用欧氏距离度量相似度。欧几里得度量(euclidean metric)(也称欧式距离)是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。
0ρ = sqrt( (x1-x2)^2+ (y1-y2)^2 )
(5.4)
similarity = 1/(op + 1)
(5.5)
最终的similarity就是相似度评价的值。
二、相似用户推荐(Python之Gensim版本)
2.1 Gensim
用Python做过文本挖掘的想必知道Gensim,首先我们看维基百科对gensim的解释:
Gensim is a robust open-source vector space modeling and topic modeling toolkit implemented in Python. It uses NumPy, SciPy and optionally Cython for performance. Gensim is specifically designed to handle large text collections, using data streaming and efficient incremental algorithms, which differentiates it from most other scientific software packages that only target batch and in-memory processing.
Gensim includes implementations of tf-idf, random projections, word2vec and document2vec algorithms,hierarchical Dirichlet processes (HDP), latent semantic analysis (LSA, LSI, SVD) and latent Dirichlet allocation (LDA), including distributedparallel versions.
也就是说,gensim是一个python的函数包,gensim包含了TF-IDF、随机投影、word2vec和document2vec算法的实现,分层Dirchlet过程(HDP),潜在语义分析(LSA)和潜在Dirichlet分配即主题模型(LDA),包括分布式并行版本。主要是用来主题建模、文档索引以及使用大规模语料数据的相似性检索,是文本挖掘在NLP领域里处理相当有效、得力的一个函数包。
2.2 数据预处理
说明:为了更广泛地使大家熟悉多种语言,接下来我用R语言来处理。
首先,以之前我们爬到的陈百强大哥的经典歌曲《偏偏喜欢你》的1024页的评论文本信息为例展开说明,R语言连接Mongodb数据库:
1.library(jsonlite)
2.library(mongolite)
3.library("openssl")
4.con <- mongo(collection = "陈百强",db = "comments", url = "mongodb://localhost")
5.mydata <- con$find()
6.dim(mydata)
得到了1025个文档,2列,第一是id,弃,第二列是comments,留。
1.1025 2
我们查看它的第二列即评论:
1.lengths(mydata['comments'][3,])
没错,一条评论信息下面有16个字段,但是R语言对这种json格式的数据处理不是很成熟,目前有rjson包,但是存在bug,其替代品RJSONIO也没有那么完善。这一阶段的数据处理我们改用Python。(这是我花费了一下午时间后的结论。多么痛的领悟。。。)
1.import pymongo
2.import pandas as pd
3.import numpy as np
4.client = pymongo.MongoClient(host='localhost', port=27017)
5.db = client['comments']
6.collection = db['陈百强']
7.# 将数据库数据转为dataFrame
8.data = pd.DataFrame(list(collection.find()))
9.num=data['comments']
10.result=pd.DataFrame(num.iloc[0])
11.for i in range(1,1025):
12. data2=pd.DataFrame(num.iloc[i])
13. result=pd.concat([result,data2],ignore_index=True)
查看其维度:
1.print(result.shape)
故有《偏偏喜欢你》下面有20500条评论,每条评论有16个字段。
1.(20500, 16)
我们选我们想要的文本字段和user字段下面的userID。
1.text.rename(columns={'w':'userID', 'x':'context'}, inplace = True)
2.text['context']=result['content']
3.for i in range(0,20500):
4. text.iloc[i,0]=result['user'].iloc[i]['userId']
得到20500行2列的数据:
1.userID context
2.0 328901978 都是有故事的人
3.1 1724358802 每天都要听至爱Danny
4.2 451250610 对呀,你就从来没喜欢过我。一点都煤油
5.3 554348857 沁入心脾的温柔
6.4 1296389446 最近好喜欢这首歌
7.5 303721726 今日点歌③.
8.6 1654009353 偏偏对你没有抵抗力
9.7 1654009353 那一次我们擦肩而过,我害怕我们会像电影里的情景一样错过,所以我没有走,我一直看着你走,可是你...
10.8 357343565 “我喜欢你”珍贵,奈何听的人不珍惜……
11.9 293896875 偏偏喜欢你 王雷雷
12.10 1510414811 对啊,这是为什么呢。
13.11 1574359988 对,好浪漫
14.12 1333924430 小时候有个小的收音机,好开心,睡觉都舍不得放下
15.13 64188725 好听
16.14 482121141 这些歌曲都是经典作品[亲亲]
17.15 427963594 偏偏喜欢你,我的翩翩夫人。
18.16 1382017788 以爱情 以时光\n\n纪贯新~❤
19.17 46656982 我和他来一家店吃饭,店里在放这首歌,他问我,你知道这首歌是什么吗?我听了一下说不知道,他说:...
20.18 425557078 幸福到疼……\r\r有一个人曾让我知道\r寄生于世原来是那么的好
21.19 568096298 超级喜欢的一首歌,偏偏喜欢你【大赞】[爱心]
22.20 412381224 他可能会单手开法拉利
23.21 301593622 [多多大笑][多多大笑][多多大笑]笑着活下去
24.22 1455906926 再见吧大渣男
25.23 1670031755 [憨笑]我比你还俗 更穷
26.24 301593622 现在一心只想搞钱,我比较俗,太穷了!
27.25 1730181168 哈哈哈哈这个年代感哦
28.26 279684331 偏偏喜欢的就是得不到!
29.27 621542625 阿Lan
30.28 1328014893 曾经他为我唱过的歌,到如今听到都心里隐隐作痛
31.29 51335946 爱,直至成伤;之后,就是永远
32.... ... ...
33.20470 62338668 nice
34.20471 62338668 愛上你永遠沒有結果 很好 我現在要放棄了 努力忘記你 不想讓自己為了一個沒結果的人那麼難受 ...
35.20472 68320201 忽然想起和一个朋友的对话,她因为家庭原因极度缺乏安全感。\n我怕…\n你怕什么?\n怕他喜欢...
36.20473 246752393 張國榮
37.20474 134205876 还记得那时地方电视台点播的一些曲子吗?重点中间无广告,那才是乐趣。某某点歌给谁谁谁……
38.20475 122104993 班固 《西都赋》“愿宾摅怀旧之蓄念,发思古之幽情。” 元稹 《赠吴渠州从姨兄士则》诗“泪因生...
39.20476 100442347 中午广播无意听到这首歌,然后特意关注了聊大广播台微博找到歌单![大哭]
40.20477 118207115 别咒王杰
41.20478 116595775 我爸只会唱一首歌,就这首歌把我妈娶到手了。[憨笑][憨笑]
42.20479 60109810 2000年生却偏偏喜欢80年代
43.20480 63357164 情爱 是什么 只有呵呵[大哭]
44.20481 62338668 [可爱]
45.20482 95087236 对啊,为何偏偏喜欢你
46.20483 68320201 [大笑]
47.20484 79282042 [皱眉][皱眉][皱眉]
48.20485 83512955 听过这首歌的人都是有故事的男人和女人[跳舞]
49.20486 67061365 上班特别累的时候听到香港的经典感觉整个世界都属于我,要是来一杯纯正的香港奶茶就更好了。[大笑]
50.20487 71401843 当年的录像厅前面就放的这首歌
51.20488 103882075 他还没死[大哭]
52.20489 62338668 我01的
53.20490 62338668 nice
54.20491 62338668 愛上你永遠沒有結果 很好 我現在要放棄了 努力忘記你 不想讓自己為了一個沒結果的人那麼難受 ...
55.20492 68320201 忽然想起和一个朋友的对话,她因为家庭原因极度缺乏安全感。\n我怕…\n你怕什么?\n怕他喜欢...
56.20493 246752393 張國榮
57.20494 134205876 还记得那时地方电视台点播的一些曲子吗?重点中间无广告,那才是乐趣。某某点歌给谁谁谁……
58.20495 122104993 班固 《西都赋》“愿宾摅怀旧之蓄念,发思古之幽情。” 元稹 《赠吴渠州从姨兄士则》诗“泪因生...
59.20496 100442347 中午广播无意听到这首歌,然后特意关注了聊大广播台微博找到歌单![大哭]
60.20497 118207115 别咒王杰
61.20498 116595775 我爸只会唱一首歌,就这首歌把我妈娶到手了。[憨笑][憨笑]
62.20499 60109810 2000年生却偏偏喜欢80年代
63.
64.[20500 rows x 2 columns]
将userID一列保存为列名,重命名行名、列名,并保存数据到文件“DealtedData.csv”中
1.names=pd.DataFrame(data.iloc[:,0])
2.data.rename(index=names.iloc[:,0],columns={2:'context'}, inplace = True)
3.data.to_csv(r'DealtedData.csv',encoding='gbk',index=True,header=True)
2.3 文本预处理
导入数据:
1.import os
2.os.chdir('G:\\项目\\网易云音乐评论\\文本挖掘') # 打印当前工作目录
3.import pandas as pd
4.data = pd.read_csv(r"DealtedData.csv",encoding='gbk', sep=',',index_col=0,header=0)
5.data.head
数据格式为下:
1.<bound method NDFrame.head of context
2.328901978 都是有故事的人
3.1724358802 每天都要听至爱Danny
4.451250610 对呀,你就从来没喜欢过我。一点都煤油
5.554348857 沁入心脾的温柔
6.1296389446 最近好喜欢这首歌
7.303721726 今日点歌③.
8.1654009353 偏偏对你没有抵抗力
9.1654009353 那一次我们擦肩而过,我害怕我们会像电影里的情景一样错过,所以我没有走,我一直看着你走,可是你...
10.357343565 “我喜欢你”珍贵,奈何听的人不珍惜……
11.293896875 偏偏喜欢你 王雷雷
12.1510414811 对啊,这是为什么呢。
13.1574359988 对,好浪漫
14.1333924430 小时候有个小的收音机,好开心,睡觉都舍不得放下
15.64188725 好听
16.482121141 这些歌曲都是经典作品[亲亲]
17.427963594 偏偏喜欢你,我的翩翩夫人。
18.1382017788 以爱情 以时光\r\r\n\r\r\n纪贯新~?
19.46656982 我和他来一家店吃饭,店里在放这首歌,他问我,你知道这首歌是什么吗?我听了一下说不知道,他说:...
20.425557078 幸福到疼……
21.有一个人曾让我知道 NaN
22.寄生于世原来是那么的好 NaN
23.568096298 超级喜欢的一首歌,偏偏喜欢你【大赞】[爱心]
24.412381224 他可能会单手开法拉利
25.301593622 [多多大笑][多多大笑][多多大笑]笑着活下去
26.1455906926 再见吧大渣男
27.1670031755 [憨笑]我比你还俗 更穷
28.301593622 现在一心只想搞钱,我比较俗,太穷了!
29.1730181168 哈哈哈哈这个年代感哦
30.279684331 偏偏喜欢的就是得不到!
31.621542625 阿Lan
32.... ...
33.62338668 nice
34.62338668 愛上你永遠沒有結果 很好 我現在要放棄了 努力忘記你 不想讓自己為了一個沒結果的人那麼難受 ...
35.68320201 忽然想起和一个朋友的对话,她因为家庭原因极度缺乏安全感。\r\r\n我怕…\r\r\n你怕什...
36.246752393 張國榮
37.134205876 还记得那时地方电视台点播的一些曲子吗?重点中间无广告,那才是乐趣。某某点歌给谁谁谁……
38.122104993 班固?《西都赋》“愿宾摅怀旧之蓄念,发思古之幽情。” 元稹?《赠吴渠州从姨兄士则》诗“泪因生...
39.100442347 中午广播无意听到这首歌,然后特意关注了聊大广播台微博找到歌单![大哭]
40.118207115 别咒王杰
41.116595775 我爸只会唱一首歌,就这首歌把我妈娶到手了。[憨笑][憨笑]
42.60109810 2000年生却偏偏喜欢80年代
43.63357164 情爱 是什么 只有呵呵[大哭]
44.62338668 [可爱]
45.95087236 对啊,为何偏偏喜欢你
46.68320201 [大笑]
47.79282042 [皱眉][皱眉][皱眉]
48.83512955 听过这首歌的人都是有故事的男人和女人[跳舞]
49.67061365 上班特别累的时候听到香港的经典感觉整个世界都属于我,要是来一杯纯正的香港奶茶就更好了。[大笑]
50.71401843 当年的录像厅前面就放的这首歌
51.103882075 他还没死[大哭]
52.62338668 我01的
53.62338668 nice
54.62338668 愛上你永遠沒有結果 很好 我現在要放棄了 努力忘記你 不想讓自己為了一個沒結果的人那麼難受 ...
55.68320201 忽然想起和一个朋友的对话,她因为家庭原因极度缺乏安全感。\r\r\n我怕…\r\r\n你怕什...
56.246752393 張國榮
57.134205876 还记得那时地方电视台点播的一些曲子吗?重点中间无广告,那才是乐趣。某某点歌给谁谁谁……
58.122104993 班固?《西都赋》“愿宾摅怀旧之蓄念,发思古之幽情。” 元稹?《赠吴渠州从姨兄士则》诗“泪因生...
59.100442347 中午广播无意听到这首歌,然后特意关注了聊大广播台微博找到歌单![大哭]
60.118207115 别咒王杰
61.116595775 我爸只会唱一首歌,就这首歌把我妈娶到手了。[憨笑][憨笑]
62.60109810 2000年生却偏偏喜欢80年代
63.
64.[20523 rows x 1 columns]>
isnull检测是否含有NaN值,有就返回True。np.any()检测df数据中是否含有等于Ture的值
1.import numpy as np
2.print(np.any(data.isnull())== True)
3.False
显示为TRUE,说明评论里有NAN值,用空str填充:
1.data=data.fillna(' ')
设置训练集和测试集合
1.from gensim import corpora, models, similarities
2.import jieba
3.# 文本集和搜索词
4.trains = list(data['context'].iloc[0:20523])
5.tests= '喜欢你'
2.4 对训练集进行分词
1.trains = [jieba.lcut(text) for text in trains]
2.trains
可以得到list形式的分词表:
1.[['都', '是', '有', '故事', '的', '人'],
2. ['每天', '都', '要', '听', '至爱', 'Danny'],
3. ['对', '呀', ',', '你', '就', '从来', '没', '喜欢', '过', '我', '。', '一点', '都', '煤油'],
4. ['沁入', '心脾', '的', '温柔'],
5. ['最近', '好', '喜欢', '这', '首歌'],
6. ['今日', '点歌', '③', '.'],
7. ['偏偏', '对', '你', '没有', '抵抗力'],..
2.5 提取词典特征数
1.[['都', '是', '有', '故事', '的', '人'],
2. ['每天', '都', '要', '听', '至爱', 'Danny'],
3. ['对', '呀', ',', '你', '就', '从来', '没', '喜欢', '过', '我', '。', '一点', '都', '煤油'],
4. ['沁入', '心脾', '的', '温柔'],
5. ['最近', '好', '喜欢', '这', '首歌'],
6. ['今日', '点歌', '③', '.'],
7. ['偏偏', '对', '你', '没有', '抵抗力'],..
查看字典里面的词语:
1.print(tfidf_vec.vocabulary_)
可见有在《偏偏喜欢你》的评论文本里一个有13651个词语。
即词典特征数为13651,feature_cnt的值。
1.Dictionary(13651 unique tokens: ['人', '故事', '是', '有', '的']...)
2.6 构建语料库
1.corpus = [dictionary.doc2bow(text) for text in trains]
2.corpus
我们得到的语料库形式为下,其中第一行评论['都', '是', '有', '故事', '的', '人']转化为了稀疏向量[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1)]。当我们使用doc2bow函数时,每一个词语会对应一个id,如:‘都’对应0,'是'对应1,'有'对应2,'故事'对应3,'的'对应4,'人'对应5, 后面的1代表在本句评论中,‘都’出现了一次,‘是’一次,‘有’一次,‘故事一次’……
1.[[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1)],
2. [(5, 1), (6, 1), (7, 1), (8, 1), (9, 1), (10, 1)],
3. [(5, 1),
4. (11, 1),
5. (12, 1),
6. (13, 1),
7. (14, 1),
8. (15, 1),
9. (16, 1),
10. (17, 1),
11. (18, 1),
12. (19, 1),
13. (20, 1),
14. (21, 1),
15. (22, 1),
16. (23, 1)],
17. [(4, 1), (24, 1), (25, 1), (26, 1)],
18. [(16, 1), (27, 1), (28, 1), (29, 1), (30, 1)],...
2.7 使用TF-IDF模型处理语料库
1.tfidf = models.TfidfModel(corpus)
2.for i in tfidf[corpus]:
3. print(i)
可以得到训练文本的TF-IDF值,以稀疏向量的形式保存:
1.[(0, 0.32184672062922548), (1, 0.73766014971005966), (2, 0.29497170498614139), (3, 0.29304380441485145), (4, 0.13870813169109303), (5, 0.40018654163321249)]
2.[(5, 0.19879141119607197), (6, 0.43291398548320181), (7, 0.1986860979407834), (8, 0.45262734719390507), (9, 0.68525962106956162), (10, 0.24318516977110011)]
3.[(5, 0.16060211474573619), (11, 0.098574217529621325), (12, 0.36067639144364333), (13, 0.42534037149410231), (14, 0.063581328755947963), (15, 0.20711773583505186), (16, 0.074812488712874464), (17, 0.248665060688224), (18, 0.16081534912048612), (19, 0.077507465039391904), (20, 0.27324683263788124), (21, 0.59516351798480016), (22, 0.27437250176801881), (23, 0.055533166748108702)]
4.[(4, 0.060614261626705232), (24, 0.64806776302591229), (25, 0.64806776302591229), (26, 0.39540139142475095)]
5.[(16, 0.1603400740935198), (27, 0.3795919475458821), (28, 0.78372267212523294), (29, 0.31693482880130575), (30, 0.33990013458011531)]
6.[(31, 0.22648623811135946), (32, 0.63332275807290517), (33, 0.50068929396716033), (34, 0.54490044866907528)]
2.8 将测试集转换为稀疏向量
1.kw_vector = dictionary.doc2bow(jieba.lcut(tests))
2.print(tfidf[kw_vector])
可以得到测试文本的TF-IDF值,以稀疏向量的形式保存:
1.[(14, 0.64759350572190955), (16, 0.76198599156861602)]
2.9 相似度计算
1.index = similarities.SparseMatrixSimilarity(tfidf[corpus], num_features=feature_cnt)
2.similarity = index[tfidf[kw_vector]]
3.for i in range(len(similarity)):
4. print('tests 与 trains%d 相似度为:%.2f' % (i + 1, similarity[i]))
得到相似度为下:
1.tests 与 trains1 相似度为:0.00
2.tests 与 trains2 相似度为:0.00
3.tests 与 trains3 相似度为:0.10
4.tests 与 trains4 相似度为:0.00
5.tests 与 trains5 相似度为:0.12
6.tests 与 trains6 相似度为:0.00
7.tests 与 trains7 相似度为:0.06
8.tests 与 trains8 相似度为:0.04
9.tests 与 trains9 相似度为:0.09
10.tests 与 trains10 相似度为:0.15
11.tests 与 trains11 相似度为:0.00
12.tests 与 trains12 相似度为:0.00
13.tests 与 trains13 相似度为:0.00
14.tests 与 trains14 相似度为:0.00
15.tests 与 trains15 相似度为:0.00
16.tests 与 trains16 相似度为:0.14
17.tests 与 trains17 相似度为:0.00
18.tests 与 trains18 相似度为:0.09
19.tests 与 trains19 相似度为:0.00
20.tests 与 trains20 相似度为:0.00
将相似度保存到文件“sim.csv”中
1.similarity = list(sim)
2.sim_file = open("sim.csv",'w')
3.for i in similarity:
4. sim_file.write(str(i)+'\n')
5.sim_file.close()
6.print(similarity)
将相似度转化为数据框,并降序排列:
1.similarity=pd.DataFrame(similarity)
2.similarity.iloc[np.argsort(-similarity.iloc[:,0]),:]
得到相似度最高的前18个:
1. 0
2.4536 1.000000
3.1803 0.784898
4.6485 0.784898
5.6134 0.784898
6.398 0.784898
7.1614 0.784898
8.8376 0.784898
9.3948 0.784898
10.1362 0.761986
11.9629 0.761986
12.5481 0.761986
13.324 0.761986
14.1632 0.761986
15.6405 0.761986
16.5091 0.761986
17.986 0.642364
18.9395 0.617391
19.3679 0.600096
查看相似度为1的评论:
1.data['context'].iloc[4536]
得到评论信息为:
1.'喜欢你'
同样,取得相似度为第2的评论信息:
1.'我喜欢你'
因此,我们得到与用户ID为76654704最相似的用户ID为380345546。
zhi
支
chi
持
zuo
作
zhe
者
长按扫码鼓励作者
▼ 长按扫码上方二维码或点击下方阅读原文
免费成为社区注册会员,会员可以享受更多权益
以上是关于基于网易云音乐评论的用户推荐系统的主要内容,如果未能解决你的问题,请参考以下文章
网易云音乐:基于RocketMQ的亿级分布式消息队列系统建设实践
网易云音乐怎么看别人的评论,特定某个人的,想知道喜欢的人在想啥。
做1.84亿用户的“知己”,网易云音乐携手飞桨让推荐系统更“贴心”