添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

源 / 数据团学社 / 聚聚

有这样一部网文~火遍大江南北,人物形象饱满,现实世界、网游世界、职业联赛三个世界线并行,且不同世界线之间互动丰富、交叉紧密,还号称网文界的“CP百科全书”~它就是 《全职高手》

当然,情节这么丰富的文自然篇幅不会小~洋洋洒洒500w字,怕不是要让诸多读者望而生畏~我,为了帮助广大读者理清人物关系,决心和大家一起通过先进的技术手段, 用文本挖掘的方式提取网文内容 ,选出优质的网文作品!!~

工具准备:jieba分词

为了提取小说中的关键词,我们需要一个工具——jieba分词。名字很形象哈,结…巴~!来看看怎么用~

i. 导入jieba包,写一句话,作为分词的素材。

1i mport jieba

2 txt = '大夏天的,开着空调,吃着西瓜,刷着微信,敲着代码,别提有多酸爽!'

ii. 直接使用jieba的cut()方法,对句子进行分词处理,返回的是一个生成器。只要是生成器,就可以用遍历来读取。

1 txt_cut = jieba.cut(txt)

2 print (txt_cut) #这里是一个生成器,可以通过遍历来解析

iii. 用斜杠分隔被解析出来的词汇,看看结果如何。

1 result = ( '/' . join (txt_cut)) #字符串 join ()方法用于将序列中的元素以指定的字符连接生成一个新的字符串。

2 print (result)

额…马马虎虎吧,虽然没啥大毛病,但有些不应该被拆的词被拆了,而有些词却应该拆分展示。这怎么办呢?

iv. 人工添加词汇作为词库,提高拆分准确率 。方法是 jieba.add_word()

1 #添加词库,提高分词准确性

2jieba .add_word (word= '吃着' )

3jieba .add_word (word= '刷着' )

4jieba .add_word (word= '敲着' )

5jieba .add_word (word= '酸爽' )

v. 把这几个词添加入词库 ,那么它们就不会被拆分了。来看一下效果:

1 txt_cut = jieba.cut(txt)

2 result2 = ( '/' . join (txt_cut))

3 print (result2)

4 "大/夏天/的/,/开着/空调/,/吃着/西瓜/,/刷着/微信/,/敲着/代码/,/别提/有/多/酸爽/!

比刚才好多了,所有的词都能够准确提炼了。但是,句子中有一些元素,比如标点符号,介词,助词等,分析时候我并不需要,我得把它们给剔除了。

vi. 写一个条件判断 删除不需要的词 。结果完美!

1 #去除停用词

2 txt_cut = jieba.cut(txt)

3 result3 = [w for w in txt_cut if w not in [ '的' , '有' , '多' , '大' , ',' , '!' ]]

4 print (result3)

5 [ '夏天' , '开着' , '空调' , '吃着' , '西瓜' , '刷着' , '微信' , '敲着' , '代码' , '别提' , '酸爽' ]

好了,基本用法介绍到这里~我们进行实战操作。

实战操作:分析素材准备

《全职高手》这部网文可是当下最火的”IP”!

i. 作品原文:

去除分析中不必要的字词,我在网上找到这个:

ii. 一份停用词表

停用词 是指在信息检索中,为节省存储空间和提高搜索效率,在处理自然语言数据(或文本)之前或之后会 自动过滤掉某些字或词 ,这些字或词即被称为Stop Words(停用词)。

停用词表部分内容展示

每部小说都有一些特殊的词汇,为提高分词准确性,我们还需要特殊词库:

iii. 一份 小说 特殊词库

搜狗细胞词库可以下载小说对应的词库

网址:https://pinyin.sogou.com/dict/

iv. 词库转换器, 把细胞词库转换成txt文本格式 ,便于处理。

原文、停用词表、特殊词库都准备好了~开始写代码!~

代码编辑:计算关键词频

i. 先导入一些会用到的模块

1 import numpy as np

2 import pandas as pd

3 import jieba

4 import wordcloud

5 from scipy.misc import imread

6 import matplotlib.pyplot as plt

7 from pylab import mpl

8 import seaborn as sns

9 mpl.rcParams[ 'font.sans-serif' ] = [ 'SimHei' ] # 指定默认字体

10 mpl.rcParams[ 'axes.unicode_minus' ]

ii. 导入停用词,转换为列表格式。

1s top_list = pd.read_csv( './停用词.txt' ,engine= 'python' ,

2 encoding= 'utf-8' ,names=[ 't' ])[ 't' ].tolist()

iii. 导入小说原文(这里需要运行约30秒,小说字太多有500W)

1f = open( './全职高手.txt' ,encoding= 'utf-8' ).read()

iv.导入词库字典,这里词很多,用load_userdict()方法批量导入,而不用前文jieba介绍中的jieba.add_word()方法

1jieba .load_userdict ( 'dict.txt' )

v. 设置一个分词功能的函数,并对小说进行分词

1 def txt_cut(f):

2 return [w for w in jieba.cut(f) if w not in stop_list and len(w)> 1 ]

4 txtcut = txt_cut(f)

vi. 分词完毕,我们对小说的词频取前二十进行简单统计,画出柱状图方便查看

1 word_count = pd.Series(txtcut).value_counts().sort_values(ascending=False)[ 0 : 20 ]

3f ig = plt.figure(figsize=( 15 , 8 ))

4 x = word_count.index.tolist()

5 y = word_count.values.tolist()

6s ns.barplot(x, y, palette= "BuPu_r" )

7 plt.title( '词频Top20' )

8 plt.ylabel( 'count' )

9s ns.despine(bottom=True)

10 plt.savefig( './词频统计.png' ,dpi= 400 )

11 plt.show()

统计结果图&表大致是这样的~

注意到“叶修”这个词,词频高达2W,可以 据此推断,他就是本书的男主角 ;又据说这本书是一部关于游戏的小说,那么词频排名第二的“君莫笑”,应该就是主人公的游戏角色。

作为资深读者的我,看到眼前二十个高频词,就已经可以推断出这部小说的剧情了!~来!我给大家造个句:

可视化展示:词云图

下面,再来玩个有趣的东西:对高频词汇画个词云图。

i. 实例化一个词云类,然后添加分词。

1 fig = plt.figure(figsize=( 15 , 5 ))

2 cloud = wordcloud.WordCloud(font_path= './FZSTK.TTF' ,

3 mask = imread( './background.png' ),

4 mode = 'RGBA' ,

5 background_color=None

6 ).generate( ' ' . join (txtcut))

类的属性介绍下:

Font_path: 词云中词的字体,中文词汇必须用中文字体,否则显示会异常。字体文件,大家可以在电脑中字体文件夹中找喜欢的。 Mask: 遮罩,设置词云图案的形状。可以导入图片设置,图片要简单,以面为主,清晰度无所谓,但分辨率一定要调高,否则做出的词云会很不清晰。图片主体不能是纯白色,因为白色被认为是背景,会被忽略识别。这里我导入一张全职高手的Logo。

Mode: 颜色模式,这里选择RGBA。

Background_color: 背景颜色。

ii. 对词的颜色做点美化

这里用到了scipy和numpy两个库的功能。我们要导入描绘底色的图片,图片尺寸要大于等于遮罩图片的分辨率。计算机会根据底色图的颜色映射到词语图上。所以底色图同样不求清晰,但颜色饱和度要高,对比度要明显!这样效果才好。

1i mg = imread( './color.png' )

2 cloud_colors = wordcloud.ImageColorGenerator(np.array(img))

3 cloud.recolor(color_func=cloud_colors)

我选了一张全职高手的全家福。

iii. 调用matplotlib接口,做一些基本设置。

1plt .imshow (cloud)

2plt .axis ( 'off' )

3plt .savefig ( './wordcloud.png' ,dpi= 400 )

4plt .show ()

绘制完成!见证奇迹吧!

人物关系:CP图

还记得一开始我说《全职高手》是一部CP百科全书吗?我们继续深入挖掘一下文中的人物关系,给他们组一组CP。

挖掘逻辑如下:

遍历文本每一行,再提取每一行中出现的人物,如果两个人物同时出现在同一行,那么他们之间人物关系密切度+1,最后,密切度最高的为最佳CP。

首先需要对词库进行一些完善,筛选出哪些词是人名

字典结构是这样的,一个词占一行,有【词,词频,词性】词频我们暂时无需关注,写个1代替。词性,我只要甄别出人名,所以,小说中的人名统一设成nr,其余的词,偷个懒,设成n(nr代表人名,n代表名词。其他词性含义可查看词性对照表)

i. 新开一个脚本,导入模块。

1 import jieba,codecs

2 import jieba.posseg as pseg

3 import pandas as pd

codecs库: 用来读取文本时,防止文本编码不统一,造成错误;

jieba.posseg: 分词后显示词性。

ii. 建立三个容器用于转换数据。

1names = {} #提取的人名,和出现的频数。

2relationships = {} #提取的人物关系。

3lineNames = []#每一行提取的人名,做缓存处理。

iii. 导入词库和文本

遍历文本每一行进行分词。排除词性不为nr,长度大于3小于2的所有词汇(通常人物名字为两个字和三个字)。

iv. 将符合要求的词汇分别添加入容器中

1 jieba.load_userdict( 'dict.txt' )

2 with codecs. open ( '全职高手.txt' , 'r' , 'utf8' ) as f :

3 n = 0

4 for line in f .readlines():

5 n+= 1

6 print ( '正在读取第{}行' .format(n))

7 poss = pseg.cut( line )

8 lineNames. append ([])

9 for w in pos s:

10 if w .flag != 'nr' or len ( w .word) < 2 or len ( w .word) > 3 :

11 #排除词性不为nr,长度大于 3 小于 2 的所有词汇

12 continue

13 lineNames[- 1 ]. append ( w .word)#以行为组,保存每行所提取的人名

14 if names. get ( w .word) is None:

15 names[ w .word] = 0

16 relationships[ w .word] = {} #把所涉及的人名作为键添加入关系字典

17 names[ w .word] += 1 #频数+ 1

v. 遍历lineNames,对每一行出现的人名进行匹配,建立人物关系

1for line in lineNames:

2 for name1 in line:

3 for name2 in line:

4 if name1 == name2:#名称相同,排除

5 continue

6 if relationships[name1].get(name2) is None:

7 relationships[ name1 ][ name2 ]= 1#对于新的人物关系,生成新的键值对。

8 else:

9 relationships[ name1 ][ name2 ] = relationships[ name1 ][ name2 ]+ 1

10 #对于已有的人物关系,密切度+1

我们最终会把人物关系通过Gephi进行模拟。而Gephi构建关系网络,需要特定格式的数据。

Gephi是一款开源免费跨平台基于JVM的复杂网络分析软件,,其主要用于各种网络和复杂系统,动态和分层图的交互可视化与探测开源工具。

vi. 这里先构建两个数组,用于归类点数据和边数据

1node = pd.DataFrame(columns=[ 'Id' , 'Label' , 'Weight' ])

2edge = pd.DataFrame(columns=[ 'Source' , 'Target' , 'Weight' ])

vii. 把清洗好的数据添加进数组中

1 for name,times in names. items ():

2 node. loc [ len (node)] = [name,name,times]

4 for name,edges in relationships. items ():

5 for v, w in edges. items ():

6 if w > 3 :

7 edge. loc [ len (edge)] = [name,v, w ]

viii. 导出数据待用

1 edge.to_csv( './edge(原).csv' , index = 0 )

2 node.to_csv( './node(原).csv' , index = 0 )

脚本编写完毕,运行一下看看。小说一共有206436行,所以,需要计算一段时间:

只分析关系密切的CP,所以我们只取边数据中 权重在100以上的数据 。按照这个标准, 整理点数据和边数据如下:

最后,我们把数据导入Gephi。

根据对美的认知,调一调颜色和布局。

好了,CP图出现了!

嗯嗯!挺有意思的!人物关系真是复杂得不得了!这里忍不住要剧透了!

叶陈CP: 叶修是战队队长,全权负责战队经营。陈果是战队老板娘,霸气侧漏。两人类似于总裁和总经理的关系吧。~~哎,这不是妥妥的霸道总裁爱上我的剧情嘛。 叶唐CP: 唐柔是富家千金,才女。不过,不小心让叶修带坏了,迷恋上了打游戏。两人算是师徒和队友关系吧。啧啧~ 叶苏CP: 这个厉害了!叶修从前认识个兄弟,叫苏沐秋,两人一起打游戏。苏沐秋有个妹妹叫苏沐橙。后来,苏沐秋死了……贵圈真乱啊!

好了,剧透结束。其实,大家有兴趣的话,可以导入更多的数据,然后根据关系网络中簇群的颜色继续研究……

那么,本次分享到此结束!希望大家少看网文,多多学习~!

-END-

转载声明:本文转载自「数据团学社」,搜索「metrodata_xuexi」即可关注。 返回搜狐,查看更多

责任编辑:

声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。