笔记
PAGE1
Python是一门十分流行的编程语言,它免费、易学,而且功能强大,在网络编程、图形用户界面编程、科学计算、数据挖掘、机器学习、人工智能等方面都有着广泛的应用。今天我们教大家用python找出《天龙八部》《倚天屠龙记》《射雕英雄传》里的主角。
正文
对于预处理得到的数据,我们会进行一些数据统计,分析数据的统计情况。对于文本数据,一个比较有用的统计数据是词频。所谓词频(Word Frequncy),指的是单词在文本中出现的次数。
词频的统计—谁是金庸笔下的主角?
具体到小说分析问题,我们可以统计小说中的各个角色的出场次数。显然,对于角色来说,主要人物的出场次数多,词频也较高,因此可以通过词频统计,大致看出小说中谁的主角光环比较强。
假定所有的小说文件的名称都是“小说名.txt”,编码都是utf8。
仍然以《天龙八部》为例,首先用codecs模块,读取小说的内容:
with codecs.open("天龙八部.txt", encoding="utf8") as f:
content = f.read()
利用人物字典character_info得到《天龙八部》中所有人物的列表chars,并用字符串的.count()方法对chars中单个人物c在content出现的次数进行计数:
chars = character_info["天龙八部"]
counts = [content.count(c) for c in chars]
为了方便对词频进行排序,我们将这两个列表变成NumPy数组:
import numpy as np
chars = np.array(character_info["天龙八部"])
counts = np.array([content.count(c) for c in chars])
利用数组的.argsort()方法对单词出现的次数counts进行排序,得到相应的下标:
idx = counts.argsort()
默认情况下,数组的排序是按照从小到大进行的。因此,可以使用idx[-10:]得到《天龙八部》中出现次数最多的10个角色的索引并利用索引i得到人名及其出现的次数:
for i in idx[-10:]:
print chars[i], counts[i]
木婉清 688
段正淳 706
王语嫣 814
慕容复 861
阿朱 961
乔峰 1086
阿紫 1108
虚竹 1584
萧峰 1724
段誉 3245
从词频统计来看,段誉荣登主角宝座
词频的绘图—谁是金庸笔下的主角?
我们还可以对词频进行绘图,从而得到更直观的结果。
在绘制词频图像之前,需要解决在Matplotlib中显示汉字的问题。
默认情况下,Matplotlib是不能直接显示汉字的。例如,直接添加汉字标题会得到如图1所示的结果:
import matplotlib.pyplot as plt
plt.title("中文")
plt.show()
图1 不能正常显示的中文标题
标题中应该显示“中文”两个字的地方被两个方块替代了,原因是Matplotlib找不到合适的中文字体去显示中文。
为此,我们需要找到一些支持中文的字体。
Windows 7 及以上的系统中,字体库的位置为 C:/Windows/Fonts,如:
l 宋体:C:/Windows/Fonts/simsun.ttc
Linux 系统可以通过 fc-list 命令查看已有的字体和相应的位置,如:
l 宋体:/usr/share/fonts/truetype/osx-font-family/Songti.ttc
也可以从网上下载字体:
l Yahei Consolas 字体:YaHei.Consolas.1.11b.ttf;
字体可以使用matplotlib.font_manager 中的FontProperties类导入:
from matplotlib.font_manager import FontProperties
font_song = FontProperties(fname="C:/Windows/Fonts/simsun.ttc")
其中,fname参数表示字体文件的位置。
这样,我们就将宋体导入了对象font_song中。
导入后,为了显示汉字我们在需要写入中文文字的函数中,加入fontProperties参数,指定显示文字的字体为font_song。例如,对于第一小节中的例子,加入参数指定宋体后,标题可以正常显示中文,得到如图2所示的结果:
import matplotlib.pyplot as plt
plt.title("中文", fontproperties=font_song)
plt.show()
图2 正常显示的中文标题
解决图像中文显示的问题后,我们回到文本分析的案例中。
为了让词频的显示更直观,可以使用plt.barh()函数绘制一个纵向的条形图,来表示《天龙八部》中出现次数前10位的人物的词频统计结果,如图3所示:
plt.barh(range(10), counts[idx[-10:]])
plt.title("天龙八部", fontproperties=font_song)
plt.yticks(range(10), chars[idx[-10:]], fontproperties=font_song)
plt.show()
其中,横轴是词出现的次数,纵轴是对应的人物名。
从图3中可以看到,词频图像的显示要比文字更为直观,不难得出“段誉是贯穿全书的主角”的猜想。
为了统计其他小说的词频,我们定义一个函数find_main_chars(),实现词频统计和绘图的过程。该函数接受两个参数:novel和num,其中novel是小说的名称,num是显示的主角个数(默认为10):
图10-3 《天龙八部》主角词频统计
def find_main_chars(novel, num=10):
# 读取文件
with codecs.open("{}.txt".format(novel), encoding="utf8") as f:
content = f.read()
# 词频统计
chars = np.array(character_info[novel])
counts = np.array([content.count(c) for c in chars])
idx = counts.argsort()
# 绘图
plt.barh(range(num), counts[idx[-num:]])
plt.title(novel, fontproperties=font_song)
plt.yticks(range(num), chars[idx[-num:]], fontproperties=font_song)
plt.show()
可以利用该函数查看其他小说中的词频统计。例如,《射雕英雄传》和《倚天屠龙记》的词频统计如图4和5所示:
图4 《射雕英雄传》主角词频统计
图5 《倚天屠龙记》主角词频统计
find_main_charecters("射雕英雄传")
find_main_charecters("倚天屠龙记")
从图4和图5中,不难得出《射雕英雄传》的主角是郭靖以及《倚天屠龙记》的主角是张无忌的结论。
以上结果说明,词频统计能够较好地找出小说中的主角人物。
关系分析
找出主角之后,我们再来运用关系分析的方法,找出下金庸先生笔下,各路英雄豪杰的微妙关系。
之前有人研究过,用Word2Vec生成的词向量存在这样的现象:
vec("北京")-vec("中国")=vec("巴黎")-vec("法国")
这种现象通常说明了一种对应关系:
“北京”之于“中国”,正如“巴黎”之如“法国”.
在gensim中,对应关系也可以使用模型的.most_similar()方法来找到。利用该方法,可以定义函数find_relationship()来寻找这样的对应关系,该函数接受a,b,c作为参数,以a和b的关系作为参考,返回与c对应具有类似关系的d。
在函数中,我们将.most_similar()方法中的postive参数设为b和c组成的列表,并加入negative参数,将其设为只有a一个元素组成的列表。.most_similar()方法返回的结果仍然是前10个相关词及其对应的相似度,这里取返回结果的第一个,作为最终找到的d。
因此,函数find_relationship()的定义为:
def find_relationship(a, b, c):
d, _ = model.most_similar(positive=[c, b], negative=[a])[0]
print "{}之于{},正如{}之于{}".format(a, b, c, d)
利用find_relationship()函数,我们可以找出人物之间存在的一些微妙关系:
find_relationship("郭靖", "黄蓉", "杨过")
find_relationship("郭靖", "华筝", "杨过")
find_relationship("段誉", "公子", "韦小宝")
find_relationship("郭靖", "降龙十八掌", "黄蓉")
郭靖之于黄蓉,正如杨过之于小龙女
郭靖之于华筝,正如杨过之于郭芙
段誉之于公子,正如韦小宝之于大人
郭靖之于降龙十八掌,正如黄蓉之于打狗棒法
最铁的关系大概是这对:
find_relationship("杨过", "小龙女", "韦小宝")
find_relationship("令狐冲", "盈盈", "韦小宝")
find_relationship("郭靖", "黄蓉", "韦小宝")
杨过之于小龙女,正如韦小宝之于康熙
令狐冲之于盈盈,正如韦小宝之于康熙
郭靖之于黄蓉,正如韦小宝之于康熙
这些关系也能佐证使用词向量模型的合理性。