python红楼梦人物词频统计_用 Python 分析《红楼梦》

Free Image on Pixabay – Landscape, Tree, Flowers, Book

啊错了,这个才是字典树……

https://www.slideshare.net/farseerfc/ukks-algorithm-of-suffix-tree

而后缀树和后缀字典树的区别就是,在后缀树中,我们要把下面只有一条边的结点去掉,然后把这个结点连接的两条边压缩成一条。比如,左图后缀字典树中的 b-a-n-a-n-a,在右图的后缀树中被压缩成了 banana 这一条边。此外,后缀树还使用了一个技巧,就是不储存边的内容,而是储存这些内容在原文中的位置。因为后缀树中的很多内容都是重复的,所以这个小技巧可以大大减少索引的大小(用专业的语言描述,它的空间复杂度是 O(n))。

后缀树又有什么用呢最大的用途就是检索字符串中间的内容。比如,假如我想查找 an 在 banana 中哪里出现过,只需要查找代表 an 的结点,就找到了所有以 an 开头的结点: anana 和 ana。由于每次出现 an 的地方都一定会产生一个以 an 开头的后缀,而所有的后缀都在后缀树中,所以这样一定能够找到所有 an 出现的位置。后缀树的强大之处在于,即使我们把 banana 换成一篇很长很长的文章,我们也能很快地进行这样的检索。

最后,我使用了 Ukkonen 算法快速地创建了整篇《红楼梦》的后缀树(用专业的语言描述 Ukkonen 算法的速度:它的时间复杂度是 O(n))。Ukkonen 算法比较复杂,所以这里我不会讲解 Ukkonen 算法,感兴趣的同学可以看看这些资料:

Ukkonen’s suffix tree algorithm in plain English

后缀树的构造方法-Ukkonen详解 – 懒人小何的日志 – 易博客

Ukkonen’s Suffix Tree Construction – Part 6 – GeeksforGeeks

有了全文索引以后,后面的程序就好做了。

4 制作字典

等等,我们不是要无字典分词吗,为什么还要制作字典实无字典分词并不是完全不用字典,只是说字典是根据原文生成的,而不是提前制作的。为了进行分词,我们还是需要先找出文章中哪些内容像是单词,才能确定如何进行切分。

那么怎么确定哪些内容像单词呢容易想到的方法就是:把所有出现次数高的片段都当成单词。听上去很有道理,所以我们可以试一试,用后缀树查询红楼梦中的所有重复的片段,然后按出现次数排个序:宝玉(3983)、笑道(2458)、太太(1982)、什么(1836)、凤姐(1741)、了一(1697)、贾母(1675)、一个(1520)、也不(1448)、夫人(1437)、黛玉(1370)、我们(1233)、那里(1182)、袭人(1144)、姑娘(1142)、去了(1090)、宝钗(1079)、不知(1074)、王夫人(1061)、起来(1059)

上面是出现频率前 20 的片段,括 内是出现次数。可以看到效果还不错,很多片段都是单词。然而,排在第六名的“了一”明明不是个单词,出现次数却比贾母还要高。可见这样的筛选方法还是有一定问题的。而且,这样被误当成单词的片段还有很多,例如“了的”、“的一”之类的。究其原因,是因为出现次数 TOP 5 的单字由高到低分别是“了、的、不、一、来”,所以它们的组合也会经常出现。为了排除这样的组合,我们可以用“凝固度”来进行进一步地筛选。

4.1 凝固度

凝固度的定义是:一个片段出现的频率比左右两部分分别出现的频率的乘积高出多少倍(注意,频率表示的是出现的比例,而频数表示的是出现的次数)。不过这句话太拗口了,还是用公式描述比较好。如果 P(AB) 是片段出现的频率,P(A) 是片段左边的字的出现的频率, P(B) 是右边的字出现的频率,那么凝固度 co 就是:

对于超过两个字的片段,可以尝试每一种拆分方法(比如“贾宝玉”有“贾/宝玉”和“贾宝/玉”两种拆分方法),然后取各种方法的凝固度的最小值。

现在我选出《红楼梦》中出现次数大于 5 的片段,对它们的凝固度做个排序:翡翠(171415.92)、茉莉(171415.92)、砒霜(171415.92)、逶迤(142846.60)、诽谤(142846.60)、徘徊(142846.60)、缱绻(142846.60)、乜斜(142846.60)、戥子(142846.60)、籰子(142846.60)、姽嫿(122439.94)、蝴蝶(122439.94)、囟门(122439.94)、槟榔(122439.94)、琵琶(122439.94)、娈童(119038.83)、筏子(119038.83)、牲口(119038.83)、踌躇(107134.95)、隄防(107134.95)

这是凝固度排名前 20 的组合,括 内是凝固度。可以看到效果还是不错的。

接着往下看,在 Top 20~100 里也基本没有不是单词的条目:腼腆、隄防、甬路、趔趄、蚊子、狮子、璎珞、疗治、羔子、跛足、尧舜、嫦娥、陛见、簸箩、梆子、粳米、竭力、栗子、撺掇、葵官、芭蕉、玲珑、俞禄、妯娌、嘁嘁喳喳、玷辱、奚落、互相、譬如、腕上、祷告、攮的、钥匙、觑着、恣意、矶上、馒头、阎王、椒房、茯苓、琪官、牡丹、恒王、凹晶、翰林、畸角、淌眼、篮子、滋味、韶华、爆竹、涨了、芍药、估量、拷问、杌子、嗓子、搪塞、晦气、麒麟、玫瑰、葫芦、躬身、恳切、崽子、盹儿、皂白、谣言、凸碧、唯唯、赫赫、簌簌、荫堂、嗤的、唠叨、努嘴、吆喝、荳官、茯苓霜、艰难

然而凝固度也有一定的局限性。再往后看的话,会发现里面还有很多片段是半个词,而它们的凝固度也挺高的。例如:“香院”(完整的词应该是“梨香院”)、“太太太太”(完整的词应该是“老太太太太”)。想想也有道理,这些片段虽然是半个词,但是它们确实也跟完整的单词一样是“凝固”在一起的。所以,光看凝固度是不够的,还要通过上下文判断这个词是否完整。

4.2 自由度

为了排除掉不完整的单词,我们可以使用自由度这个概念来继续过滤。自由度的思想是这样的:如果一个组合是一个不完整的单词,那么它总是作为完整单词的一部分出现,所以相邻的字就会比较固定。比如说,“香院”在原文中出现了 23 次,而“梨香院”出现了 22 次,也就是说“梨”在“香院”的左边一起出现的频率高达 95.7%,所以我们有把握认为”香院”不是完整的单词。而自由度描述的就是一个片段的相邻字有多么的多样、不固定。如果片段的自由度比较高,就说明这个词应该是完整的。

因为相邻字分为左侧和右侧,所以自由度也分为左右两部分。以左侧的自由度为例,计算公式就是左侧相邻字的每一种字的频率的总信息熵。也就是说,如果

(对于没学过信息熵的同学来说这个公式可能很晦涩,反正记住左侧自由度体现了左侧相邻字的多样性就可以了。)

我们把左侧自由度最低的 20 个组合拿出来,可以看到确实过滤出来了很多不是单词的内容:泪来(0.111)、在话(0.112)、慢的(0.116)、头们(0.117)、今我(0.121)、云笑(0.122)、以我(0.141)、王二(0.146)、里知道(0.146)、己也(0.151)、会子又(0.154)、太和(0.156)、用说(0.159)、嘻的(0.165)、今且(0.169)、么东西(0.187)、苦来(0.187)

(括 内为左侧自由度)

右侧也同理,有些片段明显是半个单词:有什(0.034)、周瑞家(0.053)、老太(0.065)、薛姨(0.072)、也罢(0.085)、老祖(0.093)、哭起(0.100)、在话(0.112)、听下(0.113)、些东(0.118)、林之(0.121)、个婆(0.126)、我告(0.129)、老嬷(0.139)、二夫(0.144)、邢王二(0.149)、就罢(0.154)、到自(0.169)、这会(0.175)、大嫂(0.179)

(括 内为右侧自由度)

4.3 最终的单词表

有了这些明确的评判标准,我们就可以把单词筛选出来了。我最终选择的判断标准是:出现次数大于等于 5,且凝固度、左侧自由度、右侧自由度都大于 1。然而这个标准还是太宽松了。于是,我又设计了一个公式,把这些数据综合起来:

https://zh.wikipedia.org/wiki/%E4%B8%BB%E6%88%90%E5%88%86%E5%88%86%E6%9E%90#/media/File:GaussianScatterPCA.png

现在,如果我们让 PCA 程序把这两个特征压缩成一个特征的话,算法就会寻找一条直线,使得数据点都投影到这条直线上后损失的信息最少(如果投影不好理解的话,可以想象用两块平行于直线的板子把数据点都挤压到一条线上)。在这个例子中,这条线损失信息最少的线就是图中较长的那个箭头。这样,如果我们知道了一个数据点在直线上投影的位置,我们就能大致知道数据点在压缩之前的二维空间的位置了(比如是在左上角还是右下角)。

以上是把二维数据空间压缩到一维的情况。三维压缩到二维的情况也是类似的:寻找一个二维平面,使得数据点投影到平面后损失的信息最少,然后把所有数据点投影到这个平面上去。三维压缩到一维就是把寻找平面改成寻找直线。更高维度的情况以此类推,虽然难以想象,但是在数学上是一样的。

至于算法如何找到损失信息最少的二维平面(或者直线、三维平面等等),这会涉及到一些数学知识,感兴趣的同学可以去查找一下相关的数学公式和证明。这里只要把这个算法当成一个黑箱就可以了。

9.2 重大发现/p>

现在我们可以利用 PCA,把五十个词的词频所构成的五十个维度压缩到二维平面上了。我把压缩后的数据点画出来,发现是这个样子的:

(图中横坐标是章回编 ,纵坐标是“笑道”的词频)

可以发现,“笑道”的词频是先增加再减少的,这不禁让我联想到了贾府兴衰的过程。莫非“笑道”的词频和贾府的发展状况有关趣的是,“笑道”的词频顶峰出现在第 50 回左右,而有些人从剧情的角度分析认为贾府的鼎盛时期开始于第 48、49 回,恰好重合:

《红楼梦》之“钗黛合一”带来大观园鼎盛_风之子9881198198_新浪博客

也许“笑道”这一看似平常的词汇确实侧面反应了贾府的兴衰史呢。虽然因果关系有待考证,不过想想也有一点道理,毕竟只有日子过的好的时候人们才会爱笑。

9.3 再次分析

在之前的分析中我们发现,“笑道”这个词似乎和情节的关系比较大,并且严重影响到了我们的分析。此外,“宝玉”作为一个人名,它的权重的绝对值也比较大,也可能是受到了情节的影响。因此,我决定把这两个词“拉黑”,用剩下的 48 个词的词频做特征,再次进行 PCA 分析。这次结果如下:

这次我需要把特征压缩到三维空间而非二维空间了。这是因为之前我们得到的两个成分的方差贡献率(可以理解为成分提供的信息量)分别为 44.6% 和 19.0 %,总贡献率 63.6%,算是比较高了。而现在,即使是三个成分,方差贡献率也只有 23.9%,10.6% 和 6.9% 了,总贡献率才 41.4%。可见去掉“笑道”和“宝玉”以后,从词频中发掘信息的难度提高了很多。

从图中可以看到,现在后 40 回已经不像之前那么聚集了,不过还是可以看出一点聚集的趋势。特别地,前 80 回和后 40 回在成分二和成分三上的区别比较明显。和之前一样,我们可以把在这两个成分中权重的绝对值比较大的词都找出来,看看它们的词频变化。

在成分三中,权重最小的五个单词是:没有(-0.41)、听见(-0.25)、如今(-0.21)、所以(-0.18)、我们(-0.14)。(括 内为权重)

成分二中,权重最小的三个单词是:什么(-0.30)、怎么(-0.26)、听见(-0.22)

(“听见”在排名中出现了两次。不过不知道这个发现有什么用。)

可以发现,有些词的词频确实有一些异常的变化。然而,这些变化到底有没有受到剧情影响呢觉很难说。此外,在 PCA 结果中,似乎前 40 回和中间 40 回也分开了一些,只是没有后 40 回那么明显而已。那么这是不是说明 PCA 的结果也是受到了剧情的影响呢/p>

=======================================================

如果觉得我的文章写的不错的话,打赏一块钱鼓励一下呗~

支付宝:

(手机上可以先保存到相册,然后扫码时选择从相册中识别二维码)

文章知识点与官方知识档案匹配,可进一步学习相关知识Python入门技能树首页概览211574 人正在系统学习中

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2020年11月5日
下一篇 2020年11月5日

相关推荐