Fate

数据分析:知乎专栏哔哩哔哩篇

Markdown

我用爬虫挂了一天半,从知乎的哔哩哔哩专栏中得到了200+个精华问题的所有回答,我们能够在这里得到什么呢?

word2vec简介

Word2vec 是 Google 在 2013 年年中开源的一款将词表征为实数值向量的高效工具, 其利用深度学习的思想,可以通过训练,把对文本内容的处理简化为 K 维向量空间中的向量运算,而向量空间上的相似度可以用来表示文本语义上的相似度。Word2vec输出的词向量可以被用来做很多 NLP 相关的工作,比如聚类、找同义词、词性分析等等。如果换个思路, 把词当做特征,那么Word2vec就可以把特征映射到 K 维向量空间,可以为文本数据寻求更加深层次的特征表示 。

这里的算法原理已经和机器学习挂钩了,我们不做深度剖析(算法的简介),只要使用其python包.然后介绍一下这里需要使用的方法.

  • 在使用word2vec之前请先装好codecs模块,这个模块可以免去读取文件时很多编码的麻烦,专门针对自然语言处理的编码转换,只要指定一个编码方式打开文件就ok了.

  • word2vec的导入以及使用:

1
2
3
4
5
6
7
8
9
from gensim.models import word2vec #导入模块
sentences = word2vec.LineSentence(filename) #从文件中读入语料
#sentences 指的是训练语料,
#window指词向量训练时上下文扫描窗口大小,为5就考虑前5个词和后5个词
#size指的是每个词的向量维度,
#min_count指的是最低频率,默认为5,如果一个词出现次数小于5,那么就丢弃
#workers指训练的进程数,默认是当前运行机器的处理器核数.
model = word2vec.Word2Vec(sentences, size=200,window=5,min_count=10,workers=3)
  • word2vec里面的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
print model[u'XXX'] #获取词向量,类型为`numpy.ndarray`,维数为上面指定的size
#计算与一个词的最近似topn个词,按照余弦相似度从大到小排列
result = model.most_similar(u'XXX',topn=10)
for each in result:
print each[0] , each[1]
#支持词语的加减运算(很神奇啊!) 比如'希拉里'对应'加州','川普'对应'德州',那么'希拉里'+'加州'-'川普'='德州'
model.most_similar(positive=[u"希拉里",u"加州"],negative=[u"德州"], topn=1)
#两词之间的余弦相似度
print model.similarity(u'XXX', u'YYY')
#计算两个集合之间的余弦似度
list1 = [u'今天', u'我', u'很', u'开心']
list2 = [u'空气',u'清新', u'善良', u'开心']
list_sim1 = model.n_similarity(list1, list2)
#选出集合中不同类的词语
list = [u'纽约', u'北京', u'上海', u'西安']
print model.doesnt_match(list) #自然是西瓜咯

jieba分词

  • 先利用jieba将爬下来的文本进行分词,将自定义的词典和自定义的stopwords加进来

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #部分自定义词典
    bilibibi
    noconico
    acfun
    爱奇艺
    土豆
    优酷
    哔哩哔哩
    ACG
    b站
    B站
    节奏大师
    A站
    炮姐
    御坂美琴
    2233娘
    bishi
    9bishi
    小学生
    徐逸
    陈睿
    鬼畜
    二次元
    ...
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #部分stopwords
    其实
    已经
    大家
    很多
    觉得
    喜欢
    现在
    真的
    看到
    这种
    可能
    感觉
    一下
    不能
    来说
    非常
    一点
    之后
    之前
    ...

分完词后大约还有20M的文本
Markdown

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#coding:utf-8
import jieba
import codecs
import re,os
jieba.load_userdict(u'data_analysis/mydict.txt') # 自定义词典的路径
with codecs.open(u'data_analysis/text.txt','r','utf-8') as f:
sentences = f.readlines()
stopwordfile=codecs.open("data_analysis/stopwords.txt","r",'utf-8')
stopwords=stopwordfile.readlines()
stopwords=[re.sub("\r\n|\n","",word) for word in stopwords]
stopwords.append('\n')
if os.path.exists(u'data_analysis/cut_text.txt'):
os.remove(u'data_analysis/cut_text.txt')
for sentence in sentences:
text = ' '.join([word for word in jieba.cut(sentence) if len(word)>1 and word not in stopwords])
with codecs.open(u'data_analysis/cut_text.txt','a') as f:
f.write(text)

统计词频

  • 我们先对文本中出现最多的进行一次统计,看看回答中出现的的最多的是哪些?我们这里总共有5943182个词.
    Markdown

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    下标 名称 出现次数
    97414 视频 23371
    54703 弹幕 23150
    4519 B站 22880
    11108 b站 18979
    107100 问题 11080
    53473 广告 9541
    22541 二次元 8516
    81406 用户 8511
    33925 动画 8490
    20256 中国 8114
    90403 网站 7714
    76830 游戏 7170
    33915 动漫 6748
    25484 会员 6385
    81685 电影 5912
    83461 直播 5855
    19501 东西 5832
    98289 评论 5623
    31548 出来 5205
    26480 作品 5018
    111438 鬼畜 4883
    66494 日本 4673
    32541 别人 4347
    84898 知乎 4334
    41814 回答 4155
    19316 世界 4144
    10933 bilibili 4089
    88315 粉丝 3905
    65153 文化 3866
    52613 希望 3822
  • 可以看到视频,弹幕,B站出现的次数稳居前三,同时我们自定义词典中二次元,鬼畜这些词也都在.这些数据还是比较符合我们的预期的,同时也证明了分出来的词没问题.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    #coding: utf-8
    import re
    import time
    import numpy as np
    import pandas
    import jieba
    import os
    from wordcloud import WordCloud
    import matplotlib.pyplot as plt
    from pylab import *
    import codecs
    mpl.rcParams['font.sans-serif'] = ['SimHei']
    mpl.rcParams['axes.unicode_minus'] = False
    #遍历文件中的数据
    with codecs.open(u"data_analysis/cut_text.txt",'r','utf-8') as f:
    context=f.read()
    segment = context.split()
    #去停用词
    words_df=pandas.DataFrame({'segment':segment})
    words_df.head()
    stopwords = []
    with codecs.open('data_analysis/stopwords.txt','r','utf-8') as f:
    context = f.read()
    stopwords = context.split()
    words_df=words_df[~words_df.segment.isin(stopwords)]
    #统计词频
    words_stat=words_df.groupby(by=['segment'])['segment'].agg({"number":np.size})
    words_stat=words_stat.reset_index().sort_values(by="number",ascending=False)
    print 'index','segment','number'
    for index,Series in words_stat.head(30).iterrows():
    print index,Series['segment'].decode('utf-8'),Series['number']
    words_stat[:30].plot(x='segment', y='number', kind='bar')
    plt.show()

利用word2vec进行数据挖掘

  • 我们将对b站站长bishi在window这个参数上,分别设置上下文跨度为5,10和15。找到与bishi最接近的20个关键词.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    model1 = word2vec.Word2Vec(sentences, size=200,window=5,min_count=10,workers=3)
    model2 = word2vec.Word2Vec(sentences, size=200,window=10,min_count=10)
    model3 = word2vec.Word2Vec(sentences, size=200,window=15,min_count=10)
    y_t_1 = model1.most_similar(u'bishi',topn=20)
    y_t_2 = model2.most_similar(u'bishi',topn=20)
    y_t_3 = model3.most_similar(u'bishi',topn=20)
    #输出结果
    for item in y_t_1:
    print item[0],item[1]
    print
    for item in y_t_2:
    print item[0],item[1]
    print
    for item in y_t_3:
    print item[0],item[1]
    print
  • 下图是当跨度分别为5,10,15情况下的结果.我们可以看到结果是比较符合我们的预期的,特首(另一个外号),徐逸(bishi真名),睿国(bilibili董事长),逸国,陈睿,9bishi这些词都出现了,冠名说的是b站冠名上海篮球队,体现了word2vec在聚类、找近义词方面强大的功能.在这里没有看出不同跨度下哪组结果更好,实际应用中可能要根据需要进行调节.
    Markdown

  • 我们对b站bishi,bilibili,acfun的余弦相似度进行分析.对这个结果我是不满意的,因为bilibili与b站应该是同一个词,可是相似度却只有40%.

    1
    2
    3
    4
    5
    6
    print model1.similarity(u'b站',u'bishi')
    #0.437511023039
    print model1.similarity(u'b站',u'bilibili')
    #0.405590707607
    print model1.similarity(u'b站',u'acfun')
    #0.394401775964
  • 然后我试了一下bilibili哔哩哔哩,B站,弹幕的余弦相似度,发现只有第一个令我满意.可能是语料不够充分的原因.

    1
    2
    3
    4
    5
    6
    print model1.similarity(u'bilibili',u'哔哩哔哩')
    #0.90745918569
    print model1.similarity(u'bilibili',u'B站')
    #0.381251411934
    print model1.similarity(u'bilibili',u'弹幕')
    #0.15385446278
  • 接下来做个比较有意思的实验: 弹幕+刷屏-字幕=?,结果如下,还是比较科学的,都是经常出现在弹幕中的词.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    和谐 0.669674515724
    撕逼 0.629316687584
    热闹 0.627753138542
    游客 0.595176875591
    莫名其妙 0.585232615471
    弹幕礼仪 0.583511531353
    喷子 0.583252549171
    习惯 0.570423543453
    屏蔽 0.568080067635
    动不动 0.565914690495
  • 接下来做实验,找出集合中不同类的词:输出bishi,没问题,嗯..(要是有问题我就要怀疑数据集了)

    1
    2
    3
    list = [u'b站', u'bishi', u'哔哩哔哩', u'B站',u'bilibili']
    print model1.doesnt_match(list)
    #bishi
  • word2vec的基本用法就介绍到这里了,大家也可以弄点数据来玩玩,算法细节有精力的也可以深究.

参考资料

热评文章