手把手教你完成一个数据科学小项目(8):Emoji提取与分布图谱

982

前言

请先阅读“中国年轻人正带领国家走向危机”,这锅背是不背? 一文,以对“手把手教你完成一个数据科学小项目”系列有个全局性的了解。

本系列代码统一开源在GitHub:DesertsX/gulius-projects ,感兴趣的朋友可以先行 star 哈。

截至目前我们已经完成了数据爬取数据提取与IP查询数据异常与清洗评论数变化情况分析省份提取与可视化城市提取与可视化经纬度获取与BDP可视化。本文将对评论里的
emoji 进行提取,并绘制分布图谱。

读取数据

本次主要关注评论content列,所以仅读取下面几列数据,忽略其他列。

import pandas as pd
df = pd.read_csv('Sina_Finance_Comments_All_20180811_Cleaned.csv',encoding='utf-8',usecols=['nick','time','content'])
df.head()

提取 emoji

import re
def get_emoji(content):
    pattern =re.compile(u"\[[a-zA-Z\u4e00-\u9fa5]+\]")
    result=re.findall(pattern,content)
    return result
df['emojis_list'] = df['content'].apply(get_emoji)
df.head()

将提取后的列的全部元素转换成列表。

emojis = df['emojis_list'].values.tolist()
emojis

文章所限,仅显示部分输出:

[['[费解]', '[费解]', '[费解]'],
 ['[允悲]', '[允悲]'],
 ['[嘿哈]'],
 ['[笑而不语]'],
 ['[doge]'],
 ['[doge]'],
 ['[泪]'],
 ['[doge]'],
 ['[吃瓜]'],
 ['[允悲]'],
 ['[二哈]'],
 ['[笑而不语]', '[笑而不语]'],
 ['[小黄人得意]'],
 ['[喵喵]', '[喵喵]'],
 ['[二哈]'],
 ['[doge]', '[doge]', '[doge]']]

合并嵌套列表为单一列表,之前文章和代码里已经用过很多次喽。

emojis_list = sum(emojis, [])
emojis_set = list(set(emojis_list))
num = len(emojis_set)
print(num)
print(emojis_set)

统计出emoji共76种:

76
['[打脸]', '[白眼]', '[太开心]', '[允悲]', '[爱你]', '[ok]', '[小黄人坏笑]', '[思考]', '[喵喵]', '[偷笑]', '[悲伤]', '[抱抱]', '[睡]', '[围观]', '[摊手]', '[怒]', '[衰]', '[中国赞]', '[汗]', '[鲜花]', '[小黄人得意]', '[闭嘴]', '[吃惊]', '[吐]', '[阴险]', '[晕]', '[骷髅]', '[憧憬]', '[呵呵]', '[米奇比心]', '[羞嗒嗒]', '[可怜]', '[可爱]', '[挖鼻]', '[哈哈]', '[微笑]', '[挤眼]', '[耶]', '[给力]', '[笑cry]', '[威武]', '[握手]', '[吃瓜]', '[鼓掌]', '[拜拜]', '[失望]', '[坏笑]', '[泪]', '[跪了]', '[嘿哈]', '[费解]', '[哆啦A梦汗]', '[嘻嘻]', '[亲亲]', '[皱眉]', '[哈欠]', '[怒骂]', '[攤手]', '[米奇大哭]', '[笑而不语]', '[黑线]', '[鄙视]', '[good]', '[doge]', '[作揖]', '[費解]', '[猪头]', '[二哈]', '[赞]', '[哼]', '[嘘]', '[生病]', '[哆啦A梦微笑]', '[疑问]', '[污]', '[并不简单]']

emoji 分组统计

from collections import Counter
counter = Counter(emojis_list)
print(counter.most_common())

统计结果,看看大家都喜欢发什么表情:

[('[doge]', 198), ('[二哈]', 148), ('[允悲]', 131), ('[费解]', 100), ('[摊手]', 93), ('[微笑]', 83), ('[笑cry]', 70), ('[吃瓜]', 66), ('[嘻嘻]', 44), ('[吐]', 35), ('[笑而不语]', 34), ('[并不简单]', 33), ('[跪了]', 32), ('[挖鼻]', 25), ('[拜拜]', 24), ('[喵喵]', 20), ('[太开心]', 20), ('[哈哈]', 16), ('[作揖]', 15), ('[泪]', 14), ('[good]', 13), ('[偷笑]', 10), ('[汗]', 10), ('[哆啦A梦汗]', 9), ('[失望]', 9), ('[疑问]', 9), ('[思考]', 8), ('[爱你]', 6), ('[赞]', 6), ('[憧憬]', 6), ('[污]', 6), ('[阴险]', 6), ('[白眼]', 5), ('[黑线]', 5), ('[中国赞]', 5), ('[可爱]', 5), ('[威武]', 5), ('[怒]', 4), ('[鄙视]', 4), ('[米奇大哭]', 4), ('[ok]', 4), ('[皱眉]', 4), ('[費解]', 4), ('[吃惊]', 4), ('[怒骂]', 4), ('[哼]', 4), ('[鲜花]', 4), ('[坏笑]', 3), ('[悲伤]', 3), ('[鼓掌]', 3), ('[攤手]', 3), ('[嘘]', 3), ('[晕]', 3), ('[衰]', 2), ('[呵呵]', 2), ('[抱抱]', 2), ('[小黄人坏笑]', 2), ('[可怜]', 2), ('[哈欠]', 2), ('[打脸]', 2), ('[嘿哈]', 1), ('[小黄人得意]', 1), ('[握手]', 1), ('[挤眼]', 1), ('[耶]', 1), ('[亲亲]', 1), ('[米奇比心]', 1), ('[羞嗒嗒]', 1), ('[围观]', 1), ('[猪头]', 1), ('[闭嘴]', 1), ('[生病]', 1), ('[给力]', 1), ('[哆啦A梦微笑]', 1), ('[骷髅]', 1), ('[睡]', 1)]

emoji 使用情况

y_emojis, x_counts = zip(*counter.most_common())
from pyecharts import Bar
bar = Bar("emoji 使用情况")
bar.add("emoji", y_emojis[:20], x_counts[:20], is_stack=True,is_label_show=True,xaxis_interval=0,xaxis_rotate=-45,xaxis_margin=8)
bar

为方便展示,选出top20:


这回的 emoji 没找到对应表情图,所以无法像当你点开这首《八月》的歌:9400余条评论的分析与挖掘里显示,不过从上一个项目了解如何实现也是一样的:

评论数据

拿出评论数据,方便之后绘制emoji分布图谱。

cmnts_list = df['content'].values.tolist()
cmnts_list

显示部分数据:

['[费解][费解][费解]',
 '那你以为不单身就能避免?',
 '谢谢',
 '想去声援你 结果发不出🌚',
 '锅太大,接不住',
 '[允悲][允悲]…',
 '居然这么说我们年轻人[嘿哈]',
 '老了',
 '我觉得这条博就是一个笑话……',
 '到底该不该透支消费?专家统一一下意见,在线等,急。',
 '拜托,我买再多手机穿再多名牌喝再多星巴克都没一个房贷债务高吧。推责任推这么心安理得恶不恶心啊。',
 '你们反省一下,不要做历史的罪人[笑而不语]',

将列表合并成一个字符串

cmnts = ' '.join(cmnts_list)
print(len(cmnts))
print(cmnts)

字符串长度为83252。

jieba 分词

GitHub/jieba分词前,先把上面的emojis_set里的去掉中括号后的emoji一个个都添加进自定义的词典,以免分词时被切分开。

此处需注意,如果不去掉中括号[ ],直接将整个emojis添加进词典的话,后续分词时,括号还是会被分开,可能相应的需要修改jieba源码才行(jieba分词与词性标注自定义词典支持特殊字符),但尝试后无果,于是还是采取现在的方案。

jieba/test/test_userdict.py
jieba.del_word('自定义词')或者在txt的存好,然后读入jieba.load_userdict("userdict.txt")

import jieba
emoji_drop = []
for emojis in y_emojis:
    emoji = emojis[1:-1] # 去掉括号
    jieba.add_word(emoji) # 读者可将上一行注释掉,看看分词结果
    emoji_drop.append(emoji) # 将去掉括号后的emoji单独保存
words = list(jieba.cut(cmnts))
print(len(words))
print(words)

展示部分分词结果:

54431
['[', '费解', ']', '[', '费解', ']', '[', '费解', ']', ' ', '那', '你', '以为', '不', '单身', '就', '能', '避免', '?', ' ', '谢谢', ' ', '想', '去', '声援', '你', ' ', '结果', '发不出', '🌚', ' ', '锅太大', ',', '接', '不住', ' ', '[', '允悲', ']', '[', '允悲', ']', '…', ' ', '居然', '这么', '说', '我们', '年轻人', '[', '嘿哈', ']', ' ', '老', '了',

去掉括号后的emoji_drop

['doge', '二哈', '允悲', '费解', '摊手', '微笑', '笑cry', '吃瓜', '嘻嘻', '吐', '笑而不语', '并不简单', '跪了', '挖鼻', '拜拜', '喵喵', '太开心', '哈哈', '作揖', '泪', 'good', '偷笑', '汗', '哆啦A梦汗', '失望', '疑问', '思考', '爱你', '赞', '憧憬', '污', '阴险', '白眼', '黑线', '中国赞', '可爱', '威武', '怒', '鄙视', '米奇大哭', 'ok', '皱眉', '費解', '吃惊', '怒骂', '哼', '鲜花', '坏笑', '悲伤', '鼓掌', '攤手', '嘘', '晕', '衰', '呵呵', '抱抱', '小黄人坏笑', '可怜', '哈欠', '打脸', '嘿哈', '小黄人得意', '握手', '挤眼', '耶', '亲亲', '米奇比心', '羞嗒嗒', '围观', '猪头', '闭嘴', '生病', '给力', '哆啦A梦微笑', '骷髅', '睡']

NLTK 分布图谱

分布图谱在《当你点开这首《八月》的歌:9400余条评论的分析与挖掘》项目时,就想实现,可惜一直没成功,notebook里保留了尝试的代码,且整个代码太杂乱,需如本系列一样后续拆分开和润色。

也是因缘际会,想本系列项目结束后,下一个系列就来玩玩热门电视剧、热门电影,也罗列了许多切入点,感觉要是能搞出来,还是不错的。这回也先绘制了于正的热门清宫剧《延禧攻略》里的一些主要人物在小说文本中的分布图谱。


扯远了,因为上述尝试成功后,这回也用到emoji的分布上来。虽然评论数据是拼接到一起,因而分布图谱的可解释性一般,权当尝个鲜、玩玩新花样。

import matplotlib.pyplot as plt
%matplotlib inline
import nltk
from nltk.draw.dispersion import dispersion_plot

plt.rcParams['font.sans-serif'] = ['SimHei']
ntext = nltk.Text(words)
ntext.dispersion_plot(emoji_drop[:15])

上面是top15的分布图谱,结合pyecharts的柱形图一起看,风味尤佳:

而全部emoji的分布图谱,纵坐标太密集,但整张图有种说不出的美感,逃……

ntext.dispersion_plot(emoji_drop)

你听说过安利吗?

本系列代码统一开源在GitHub:DesertsX/gulius-projects ,感兴趣的朋友可以先行 star 哈。

本系列文章:
“中国年轻人正带领国家走向危机”,这锅背是不背?
手把手教你完成一个数据科学小项目(1):数据爬取
手把手教你完成一个数据科学小项目(2):数据提取、IP 查询
手把手教你完成一个数据科学小项目(3):数据异常与清洗
手把手教你完成一个数据科学小项目(4):评论数变化情况
手把手教你完成一个数据科学小项目(5):省份提取与可视化
手把手教你完成一个数据科学小项目(6):城市提取与可视化
手把手教你完成一个数据科学小项目(7):经纬度获取与BDP可视化