最近和舍友看完了去年大火的电视剧【人民的名义】,看完觉得里面的人物关系很有意思,决定对其分析分析,也顺便测试一下早前使用过的一些模型(例如word2vec)效果是否能达到预期。
1.获取数据
进行分析之前首先需要获取剧情的文本,因为没有看过小说,为了尽量接近自己和大部分人所熟悉的剧情,这里爬取从百度百科上的每一集的剧情,针对已更新的剧情文本进行分析。利用python的urllib2(python3.3后改为urllib.request)和BeautifulSoup包可以很快的爬下剧情文本,保存为rmdmy.txt文档,顺便将出现的人物名字也一起爬下来,后面进行预处理和分析中涉及到的分词、实体属性对齐和社交网络分析等都将会用到。
# -*- coding: utf-8 -*-
@author: wangyao
#改变默认工作路径
import os
os.chdir(r"C:UserswangyaoDesktop人民的名义")
##爬取百度百科剧情
import urllib.request
from bs4 import BeautifulSoup
import re
import pandas as pd
url = "https://baike.baidu.com/item/%E4%BA%BA%E6%B0%91%E7%9A%84%E5%90%8D%E4%B9%89/17545218"
import sys
import importlib
importlib.reload(sys)
response = urllib.request.urlopen(url)
con = response.read()
#使用beautifulsoup中的html解析器
cont = BeautifulSoup(con,"html.parser")
content = cont.find_all('ul',{'id':'dramaSerialList'})
content = str(content)
##去掉HTML标签
content1 = re.sub(r']+>','',content)
f = open('rmdmy.txt','w',encoding= 'utf-8') #直接用open打开会报错,需要指定编码方式
f.write(content1)
#爬取名字
f = open('rmdmy_name.txt','a',encoding= 'utf-8')
name_content = cont.find_all("dl",attrs={"class": "info"})
for i in name_content:
name_d = i.get_text().strip().split(u' ')[0]
name = name_d.split(u'xa0')[2]
#加decode()byte和str才能相加
f.write(name.encode('utf-8').decode()+'
文本文件如下所示:
rmdmy.txt
rmdmy_name.txt
2.文本预处理
将剧情爬下来后需要对文本进行预处理,主要包括分句、分词、去掉一些特殊符号和停用词、实体对齐和属性对齐等。如果一个人可能在剧中有不同的名字,这时候就需要进行统一。为了尽量正确的切分一些固定名称,需要导入自定义词典,主要包含一些人名、地名和组织名称等(例如这里需要加入侯亮平,汉东省,汉东大学,山水集团,大风厂等等)。此外,在提取文本特征时需要去掉一些停用词,以提高分析的准确度。经过一系列处理后得到比较干净的文本分词结果,然后就可以在此基础上进行深入的分析。
#文本预处理
import jieba
jieba.load_userdict('rmdmy_dict.txt')#自定义词典
stopword = [line.strip() for line in open('StopwordsCN.txt',encoding= 'utf-8').readlines()] #简体中文停用词
fr = open('rmdmy.txt','r',encoding= 'utf-8')
con = [fr.readlines()]
分词,并去掉特殊字符、词语
fw = open('rmdmy_content.txt','w',encoding= 'utf-8')
for i in con[0]:
#if len(i.decode('utf-8'))<=10:
if len(i)<=10:
pass
w1 = i.split("。")#按句号分句
for j in w1:
w2 = re.sub(r',|。|?|:|“|”|!','',j.strip())#去掉特殊字符
#w1 = re.sub(name1,name2,w1) #实体对齐
w3 = list(jieba.cut(w2))#分词
w4 = [w for w in w3 if w not in stopword]#去掉停用词
outstr = ''
for word in w4:
outstr +=word
outstr +=' '
fw.write(outstr.strip().encode('utf-8').decode())
fw.write('
fw.close()
预处理结果:
rmdmy_content.txt
3.人物出现频次和社交网络关系
先看一下剧中出场次数较多的关键人物有哪些,根据之前爬下来的名字列表,统计其在文本中出现的次数,通过matplotlib包画出出现次数最多的10个关键人物如图所示,可以发现侯亮平出现次数最多,共483次,其次李达康出现了226次,再次是高育良出现了211次,祁同伟202次。整部剧穿插的几大事件都在围绕着这四个人展开,而沙瑞金虽然也是贯穿全剧的重要人物,出场次数也很多(148次),但是大部分事件里都是出来打酱油的,所以次数还低于大风厂事件的蔡成功。
#人物出场次数统计
import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
font_yahei_consolas = fm.FontProperties(fname = 'simsun.ttc')
#引入字体,否则文字显示不出来
#python 字符串转列表 list 出现的解决方法(网上)
##文件内容 lisi
#lock = open("lock_info.txt", "r+",encoding="utf-8")
#lock_line = lock.readline()
#lock_list = lock_line.split(",")
#print(lock_list)
#y = lock_line.encode('utf-8').decode('utf-8-sig')
#print(y)
##打印结果如下
#['lisi']
#lisi
#自己测试,在notepad++上把编码从UTF-8编码模式改成UTF-8无BOM编码模式,ufeeff就会消失
with open('rmdmy_dict.txt',encoding= 'utf-8') as f1:
data1 = f1.readlines()
with open('rmdmy_content.txt',encoding= 'utf-8') as f2:
data2 = f2.read()
人物出场频次条形图:
人物出场次数
再来看看剧中人物的社交关系情况,采用以句为单位来进行分析(有时候也以段落为单位来识别人物关系,但采集的文本每集只有一个段落,所以不适用),即如果两个人同时出现在一句话中,那说明他们之间肯定有某种联系。因此可以得到他们的社交网络关系。通过求得的共现矩阵,使用Gephi画出下面的社交网络关系图,图中边的粗细代表关系的密切程度,边越粗表示两人的关系越密切,而名字的大小可以表示为该人的社交人脉强弱情况。
#社交网络关系(共现矩阵)
f2 = open('rmdmy_content.txt','r',encoding= 'utf-8')
word = f2.readlines()
name = data1
#name = data1[1:]
#总人数
wordcount = len(name)
#初始化128*128值全为0的共现矩阵
cormatrix = [[0 for col in range(wordcount)] for row in range(wordcount)]
#遍历矩阵行和列
for colindex in range(wordcount):
for rowindex in range(wordcount):
cornum = 0
#如果两个人名字在同一句话里出现,那么共现矩阵中两个人对应的值加1
for originline in word:
if name[colindex].strip() in originline and name[rowindex].strip() in originline:
cornum += 1
cormatrix[colindex][rowindex] = cornum
cor_matrix = np.matrix(cormatrix)
for i in range(len(name)):
cor_matrix[i,i] = 0
social_cor_matrix = pd.Dataframe(cor_matrix, index = name,columns = name)
#把共现矩阵存进excel
social_cor_matrix.to_csv('social_cor_matrix.csv')
social_contact = pd.Dataframe(columns = ['name1','name2','frequency'])
#共现频率
for i in range(0,len(name)):
for j in range(0,len(name)):
if i 0:
social_contact.loc[len(social_contact),'name1'] = name[i]
social_contact.loc[len(social_contact)-1,'name2'] = name[j]
social_contact.loc[len(social_contact)-1,'frequency'] = cormatrix[i][j]
social_contact.to_excel('social_contact.xlsx',index = False)
社交情况:
社交网络
4.走进‘大风厂’事件
接下来重点探索一下我比较感兴趣的“大风厂”事件,先通过关键字抓取出相关剧情,然后使用python的wordcloud包生成词云,wordcloud可以导入图片自定义词云的形状,非常方便,但是需要注意中文编码和字体的问题,否则生成的词云会显示成乱码。
#大风厂(感兴趣的关键字,可能需要加入到词典中)
text = []
#遍历每句话
if '大风厂' in line:
text.append(line)
#词频统计
dict_dz = {}
dz1 = i.split(' ')
for w in dz1:
w1 = w.strip()
if dict_dz.__contains__(w1) :
dict_dz[w1] += 1
dict_dz[w1] = 1
#生成text
text1 = ''
dz2 = i.split(' ')
for w in dz2:
text1 =text1 +' '+ w
#生成词云图
from wordcloud import WordCloud,STOPWORDS,ImageColorGenerator
#读取背景图片信息保存为array
background_Image = plt.imread('c1.jpg')
font = 'msyh.TTF'
#设置字体格式路径,不然显示不了中文,
#可以改成r'C:WindowsFontsxxxx.ttf'来切换其他字体,这边我们把文件放在默认文件夹中。
#选择已经有的字体,根据词频否则生成图片的时候会报错:OSError: cannot open resource
wc = WordCloud(background_color = 'white',mask = background_Image,
max_words = 2000,stopwords = STOPWORDS,font_path = font,
max_font_size = 80,random_state = 42,scale = 1.5).generate(text1)
#这种方法和上面直接generate()的结果相同,但是传入的数据格式不同,
#这个函数传入的是要给字典,key(键)为词,value(值)为出现频率。
#wc.generate_from_frequencies(dict_dz)
#根据图片生成词云颜色,这里选择显眼的颜色
#如果需要黑白灰的词云颜色就把'#'删除
#image_colors = ImageColorGenerator(background_Image)
#wc.recolor(color_func = image_colors)
plt.imshow(wc)
plt.axis('off')
wc.to_file('c2.jpg') #保存图片
生成的词云图:
wordcloud
词云中词语越大代表和大风厂这个词相关度越高,可以看出和大风厂关系最紧密的有:蔡成功,陈岩石,郑西坡,李达康,职工股权,侯亮平,高小琴,山水集团等
4.1.基于TF-IDF提取关键词
上面的词云图表示了大风厂同时出现频数多的词,但出现频数多的词并不能代表是文本中的关键词,故使用TF-IDF进行关键词提取。TF-IDF权重通过计算词频和逆向文件频率来计算,这里直接利用jieba分词工具进行提取,列出20个关键词如下表所示:
【蔡成功,李达康,郑西坡,陈岩石,侯亮平,赵东来,沙瑞金,陈清泉,职工,高小琴,山水集团,尤瑞星,郑乾,欧阳菁,股权,打电话,常成虎,京州,陈海,郑胜利】
可以发现与大风厂相关的主要人物都列出来了,此外,还有一些特别词,如山水集团,京州,职工,股权等,通过这些关键词我们可以比较清楚的知道有关大风厂的大部分信息。我们可以推测出:大风厂事件很可能和山水集团还有职工股权纠纷有关,其事件主要涉及到的人是山水集团、京州公务员、大风厂职工,各部分人在事件中扮演不同的角色。如果想看到每个词具体的TF-IDF权重也可以利用scikit-learn包进行计算,然后再根据权重的大小进行重要性排序。
#基于tf-idf提取关键词
from jieba import analyse
tfidf = analyse.extract_tags
#analyse.set_stop_words('stop_words.txt') #使用自定义停用词集合
text_dz = ''
for l in text:
text_dz += l
text_dz += ' '
keywords = tfidf(text_dz,topK=20)
print (keywords)
4.2.运用word2vec挖掘语义相似关系
由于文本分析中也经常会用到word2vec将文本转化为词向量的形式后来挖掘词语语义上的相似关系。这里我们使用word2vec来测试一下模型效果。导入gensim库后,将文本转化为模型输入的形式后进行训练,然后就可以得到每个词的向量形式。
4.2.1 先简单介绍一下word2vec的基本使用:
训练模型的定义:
from gensim.models import Word2Vec
model = Word2Vec(sentences, sg=1, size=100, window=5, min_count=5, negative=3, sample=0.001, hs=1, workers=4)
#参数解释:
#其中的sentences是句子列表,而每个句子又是词语的列表,即list[list]类型。
#1.sg=1是skip-gram算法,对低频词敏感;默认sg=0为CBOW算法。
#2.size是输出词向量的维数,值太小会导致词映射因为冲突而影响结果,值太大则会耗内存并使算法计算变慢,一般值取为100到200之间。
#3.window是句子中当前词与目标词之间的最大距离,3表示在目标词前看3-b个词,后面看b个词(b在0-3之间随机)。
#4.min_count是对词进行过滤,频率小于min-count的单词则会被忽视,默认值为5。
#5.negative和sample可根据训练结果进行微调,sample表示更高频率的词被随机下采样到所设置的阈值,默认值为1e-3。
#6.hs=1表示层级softmax将会被使用,默认hs=0且negative不为0,则负采样将会被选择使用。
#7.workers控制训练的并行,此参数只有在安装了Cython后才有效,否则只能使用单核,anaconda会自带Cython。
训练后的模型保存与加载:
model.save(fname)
model = Word2Vec.load(fname)
模型使用
model.most_similar(positive=['woman', 'king'], negative=['man'])
#woman+king-man的词向量结果:输出[('queen', 0.50882536), ...]
model.doesnt_match("breakfast cereal dinner lunch".split())
#输出'cereal' ,分出不是一类的词
model.similarity('woman', 'man')
#两个词的相似度,输出0.73723527
model['computer'] # raw numpy vector of a word
#某个词的特征,输出array([-0.00449447, -0.00310097, 0.02421786, ...], dtype=float32)
4.2.2 分析与‘大风厂’相似的词语关系
#word2vec
import gensim
sentences = []
if line.strip() != '':
sentences.append(line.strip().split(' '))
model = gensim.models.Word2Vec(sentences,size = 100,window = 5,min_count = 5,workers = 4)
例如打印出“大风厂”的向量如输出结果所示。
print (model['大风厂'])
向量图
我们也可以输出通过word2vec生成向量之后,和‘大风厂’最相似的向量
#这里我们输出相似度最高的18个(本来取了20个,最后两个词无特别含义,这里我们topn取18)
for k,s in model.most_similar(positive = ['大风厂'],topn=18):
print (k,s)
关联词向量
最后,我们测试一下word2vec的效果,由于篇幅有限这里就不介绍word2vec原理了,具体可以去看peghoty大神的word2vec系列博客。https://blog.csdn.net/itplus/article/details/37969635
【 需要注意的是:如果使用word2vec建议不要去除停用词,因为word2vec用于发现上下文的关系,如果去除了停用词,生成的词向量可能会受影响,最后生成的词向量差异过小没有区分度,这里我们为了方便还是使用去除停用词的语料,这导致了出现的关联词向量相似度两极分化的现象。另外在深度学习中也是不需要去除停用词的,但是去除了模型结果会有略微提升】
word2vec模型的优点在于不仅考虑了语境信息还压缩了数据规模。了解word2vec的人都知道,他的强大之处在于可以利用基本代数公式来发现单词之间的关系(比如,“国王”-“男人”+“女人”=“王后”)。所以word2vec生成的词向量很明显可以应用于:代替词袋用来预测未知数据的情感状况。
现在这些词向量已经捕捉到上下文的信息,我们来看一下效果:
计算一个词,该词的词向量和词向量(山水集团+大风厂-高小琴)最接近。
由于高小琴是山水集团的boss,而蔡成功是大风厂的boss,那么按照word2vec的原理我们可以自己推理出,这个词应该是'蔡成功'。
r = model.most_similar(positive = ['山水集团','大风厂'],negative=['高小琴'],topn=1)
print (r)
结果为:
word2vec运算结果.png
[('蔡成功', 0.9983329772949219)]
和预期结果一样,这就是word2vec的强大之处。
以上就是本篇文章【gephi和python_python+nlp+Gephi 分析电视剧【人民的名义】】的全部内容了,欢迎阅览 ! 文章地址:http://dfvalve.xrbh.cn/news/2024.html 资讯 企业新闻 行情 企业黄页 同类资讯 首页 网站地图 返回首页 迅博思语资讯移动站 http://keant.xrbh.cn/ , 查看更多