取名10行代码看懂红楼梦,是将介绍使用python代码来读红楼梦获取其主要人物。这里的思想就是词频统计,通过分析红楼梦小说文字中出现最多的词语,来概括说明红楼梦的核心人物和事情。实际上如果你能跟着往下看,就开始进入了自然语言处理的一些基础知识。

在正式进入读红楼梦之前,需要先铺垫一些词频统计相关知识。因此首先从英文的词频统计操作开始,其中的思想用到了大数据分布式处理里的mapreduce框架,在该框架中主要包括两个任务:map(映射)和reduce(规约)。这里不具体讨论MapReduce的思想和处理流程,我们来看一下在python中实现wordcount词频统计任务,进而来体验一下其基本思路。后面再来实现中文的词频统计分析,进而看懂红楼梦。

英文文章的词频统计

词频统计任务是一个非常常见的任务,也是相对较为简单的程序。任务就是从一段文字中将单词出现的次数统计出来,例如从ChinaDaily英文网站上关注一段新闻:

CHENGDU -- Rescuers have located 14 miners trapped underground in a flooded coal mine in Southwest China's Sichuan province, local authorities said Sunday.

The rescuers are clearing the shaft and drilling a deep hole to reach the trapped miners. They are also trying to pump and block water in a bid to prevent the rising of underground water levels and are sending more oxygen down the underground shaft.

The accident occurred at 3:26 pm Saturday at the Shanmushu coal mine owned by Sichuan Coal Industry Group in Gongxian County when 347 miners were working underground. A total of 329 escaped and four were killed.

Nearly 200 rescuers are racing against the clock to reach the trapped miners.

Due to communication interruptions in some mining areas, the workers were not immediately located. But through their consistent efforts, the rescue workers have finally located the remaining miners。

那这段话有多少个单词呢?最笨的办法就是一个个的数,但这显然不是我们想要的方式。既然有python,我们可以尝试使用程序来解决这个问题。

我们先来理清一下思路顺序。

(1)首先需要将这段文字从网站上拷贝下来或者爬取下来保存成文本文件;

(2)然后在python中读取该文件开始处理这个段落。因为是单词统计,很明显单词与单词之间主要分割标记就是空格,如果使用空格来分割段落文字,就可以将段落打散为一个个的单词列表了。不过同时看到段落中除了空格外,还有标点符号以及数字,这些也都需要去除。在整理好单词列表后,就可以使用map方式将所有单词与其出现的次数构建成<单词,次数>这种key-value结构对。

(3)然后使用reduce规约思想将这种结构对进一步处理,即将相同单词的次数累加,获得每个单词出现的频率。

根据思路我们来组织程序代码:

第一步,简单点,将新闻段落复制粘贴到记事本里,保存为news.txt文件。这个部分就不需要代码了。

第二步,python读这个文件,将段落读出来。这里定义个函数为readPara,即读取段落文字,函数参数为filename。定义完函数后就可以测试一下。

#定义一个读取段落文字的函数
def getPara(filename):with open(filename,'r') as f:content=f.readlines()return content#给定文本文件的位置
file="news.txt"
print(getPara(file))

测试结果返回一个列表,具体如下:

["CHENGDU -- Rescuers have located 14 miners trapped underground in a flooded coal mine in Southwest China's Sichuan province, local authorities said Sunday.n", 'The rescuers are clearing the shaft and drilling a deep hole to reach the trapped miners. They are also trying to pump and block water in a bid to prevent the rising of underground water levels and are sending more oxygen down the underground shaft.n', 'The accident occurred at 3:26 pm Saturday at the Shanmushu coal mine owned by Sichuan Coal Industry Group in Gongxian County when 347 miners were working underground. A total of 329 escaped and four were killed.n', 'Nearly 200 rescuers are racing against the clock to reach the trapped miners.n', 'Due to communication interruptions in some mining areas, the workers were not immediately located. But through their consistent efforts, the rescue workers have finally located the remaining miners。']

第三步,开始分割段落为单词。这里的任务包括去除其中的非单词字符,如标点符号和数字。

这个段落稍微有点复杂,那就是最后一个单词miners那有个中文的句号,需要先将其清除。清除的办法采用分割方法split函数:split('。')。分割后获得的为两个列表,这里只需要取第一个列表即可,因为第二个列表为标点符号句号。

for para in content:paraText=para.split('。')paraText=para[0]

然后在剩下的段落文本paraText中采用英文的句号继续分割:split('.'),形成多个句子的列表。

for para in content:paraText=para.split('。')paraText=para[0]paraList=paraText.split('.')

紧接着就可以将句子打散为单词了。不过其中还有一些换行符号和非英文单词字符,可以使用python自带的isalpha函数来判断,isalpha函数就是用于判断整个单词是否都是字母组成,如果判断为真,说明就是单词,如果不是,就说明不是单词。这样做问题都不大,不过在本次段落中出现了一个China's,被误杀了。这种连接拼写确实不是很好处理,这里也只能先舍弃掉。后面再想办法来处理。

打散后,然后将单词再一一的添加到一个新的列表中,这样形成整个段落的英文单词列表。所以可以先定义一个words_list空列表,然后后面使用append方法将打散的单词添加进去。

同时在单词处理的时候,大小写还是需要注意的,这里将所有大写都变成小写即可。使用方法就是单词作为字符串对象,使用其lower函数即可。

整个过程的代码组织如下:

def mapper(filename):words_list=[]                   #定义一个空列表with open(filename,'r') as f:   #打开段落所在的文本文件content=f.readlines()       #从头读到尾并保存到content列表中。默认会按段落分割for para in content:            #对每一个段落列表进行处理para=para.split('。')       #如果存在中文句号,将整个段落按句号分割,形成两个大的列表para0=para[0].split('.')    #取第一个列表,并使用英文句号分割,形成多个不含句号的文本列表for item in para0:          #对每一个文本列表进行处理words=item.split(' ')   #采用空格分割方式将文本列表打散为单词或者其他字符for word in words:      #对每个单词或其他字符组合进行判断if word.isalpha()==False:  #如果不是单词时continue               #就不执行下面的操作words_list.append(word.lower())    #将所有的英文单词变成小写后一个个添加到words_list列表中print(words_list)               #打印测试查看最终获得的单词列表

运行后结果如下:

['chengdu', 'rescuers', 'have', 'located', 'miners', 'trapped', 'underground', 'in', 'a', 'flooded', 'coal', 'mine', 'in', 'southwest', 'sichuan', 'local', 'authorities', 'said', 'sunday', 'the', 'rescuers', 'are', 'clearing', 'the', 'shaft', 'and', 'drilling', 'a', 'deep', 'hole', 'to', 'reach', 'the', 'trapped', 'miners', 'they', 'are', 'also', 'trying', 'to', 'pump', 'and', 'block', 'water', 'in', 'a', 'bid', 'to', 'prevent', 'the', 'rising', 'of', 'underground', 'water', 'levels', 'and', 'are', 'sending', 'more', 'oxygen', 'down', 'the', 'underground', 'shaft', 'the', 'accident', 'occurred', 'at', 'pm', 'saturday', 'at', 'the', 'shanmushu', 'coal', 'mine', 'owned', 'by', 'sichuan', 'coal', 'industry', 'group', 'in', 'gongxian', 'county', 'when', 'miners', 'were', 'working', 'underground', 'a', 'total', 'of', 'escaped', 'and', 'four', 'were', 'killed', 'nearly', 'rescuers', 'are', 'racing', 'against', 'the', 'clock', 'to', 'reach', 'the', 'trapped', 'miners', 'due', 'to', 'communication', 'interruptions', 'in', 'some', 'mining', 'the', 'workers', 'were', 'not', 'immediately', 'located', 'but', 'through', 'their', 'consistent', 'the', 'rescue', 'workers', 'have', 'finally', 'located', 'the', 'remaining', 'miners']

除了上述说的China's外,其他的单词都进入了列表。

第四步,开始统计单词出现的次数,处理的时候可以先定义个空字典,然后读取列表中的单词,如果在字典中已存在,则将其出现次数累加,如果不存在,则将其次数设定为1:

     for word in words_list:if word in words_dict:words_dict[word]+=1else:words_dict[word]=1

这里我们可以单独定义一个函数如reduce,其输入为第三步的单词列表。

def reduce(words):words_dict={}for word in words:if word in words_dict:words_dict[word]+=1else:words_dict[word]=1return words_dict 

将第三步的单词列表传入reduce函数,打印一下处理结果如下:

{'chengdu': 1, 'rescuers': 3, 'have': 2, 'located': 3, 'miners': 5, 'trapped': 3, 'underground': 4, 'in': 5, 'a': 4, 'flooded': 1, 'coal': 3, 'mine': 2, 'southwest': 1, 'sichuan': 2, 'local': 1, 'authorities': 1, 'said': 1, 'sunday': 1, 'the': 12, 'are': 4, 'clearing': 1, 'shaft': 2, 'and': 4, 'drilling': 1, 'deep': 1, 'hole': 1, 'to': 5, 'reach': 2, 'they': 1, 'also': 1, 'trying': 1, 'pump': 1, 'block': 1, 'water': 2, 'bid': 1, 'prevent': 1, 'rising': 1, 'of': 2, 'levels': 1, 'sending': 1, 'more': 1, 'oxygen': 1, 'down': 1, 'accident': 1, 'occurred': 1, 'at': 2, 'pm': 1, 'saturday': 1, 'shanmushu': 1, 'owned': 1, 'by': 1, 'industry': 1, 'group': 1, 'gongxian': 1, 'county': 1, 'when': 1, 'were': 3, 'working': 1, 'total': 1, 'escaped': 1, 'four': 1, 'killed': 1, 'nearly': 1, 'racing': 1, 'against': 1, 'clock': 1, 'due': 1, 'communication': 1, 'interruptions': 1, 'some': 1, 'mining': 1, 'workers': 2, 'not': 1, 'immediately': 1, 'but': 1, 'through': 1, 'their': 1, 'consistent': 1, 'rescue': 1, 'finally': 1, 'remaining': 1}

第五步,由此我们将每个单词出现的次数都统计了一下,最后需要对该字典按value方式排序,出现次数多的排列在前面,少的排列在后面,代码为:

def reduce(words):words_dict={}for word in words:if word in words_dict:words_dict[word]+=1else:words_dict[word]=1words_dict=sorted(words_dict.items(),key=lambda x:x[1],reverse=True)  #字典按value排序return dict(words_dict)    #排序后为元组列表,使用dict函数将其转换为字典

再来测试结果就得到了:

{'the': 12, 'miners': 5, 'in': 5, 'to': 5, 'underground': 4, 'a': 4, 'are': 4, 'and': 4, 'rescuers': 3, 'located': 3, 'trapped': 3, 'coal': 3, 'were': 3, 'have': 2, 'mine': 2, 'sichuan': 2, 'shaft': 2, 'reach': 2, 'water': 2, 'of': 2, 'at': 2, 'workers': 2, 'chengdu': 1, 'flooded': 1, 'southwest': 1, 'local': 1, 'authorities': 1, 'said': 1, 'sunday': 1, 'clearing': 1, 'drilling': 1, 'deep': 1, 'hole': 1, 'they': 1, 'also': 1, 'trying': 1, 'pump': 1, 'block': 1, 'bid': 1, 'prevent': 1, 'rising': 1, 'levels': 1, 'sending': 1, 'more': 1, 'oxygen': 1, 'down': 1, 'accident': 1, 'occurred': 1, 'pm': 1, 'saturday': 1, 'shanmushu': 1, 'owned': 1, 'by': 1, 'industry': 1, 'group': 1, 'gongxian': 1, 'county': 1, 'when': 1, 'working': 1, 'total': 1, 'escaped': 1, 'four': 1, 'killed': 1, 'nearly': 1, 'racing': 1, 'against': 1, 'clock': 1, 'due': 1, 'communication': 1, 'interruptions': 1, 'some': 1, 'mining': 1, 'not': 1, 'immediately': 1, 'but': 1, 'through': 1, 'their': 1, 'consistent': 1, 'rescue': 1, 'finally': 1, 'remaining': 1}

上述五步整个代码完整组织如下:

def mapper(filename):words_list=[]with open(filename,'r') as f:content=f.readlines()for para in content:para=para.split('。')para0=para[0].split('.')for item in para0:words=item.split(' ')for word in words:if word.isalpha()==False:continuewords_list.append(word.lower())return words_listdef reduce(words):words_dict={}for word in words:if word in words_dict:words_dict[word]+=1else:words_dict[word]=1words_dict=sorted(words_dict.items(),key=lambda x:x[1],reverse=True)return dict(words_dict)filename="new.txt"     #文件资源位置
wordlist=mapper(filename)   #获取单词列表
wordCount=reduce(wordlist)  #对词频进行统计
print(wordCount)   #打印结果

上述过程就是单文件词频统计,在段落中出现次数最多的是the单词,这个对于段落内容理解没有意义,第二多的是miners、in 和to,这个miners应该是有意义的,in和to也是没有意义的单词。第三多的是underground,a,are和and,这里underground也是有意义的,后两个都没有意义。所以从前面排序结果来看,大概可以知道这个段落里讲的是underground miners,也就是地下挖矿的人,和他们有关。如果进一步往下看的话,出现两次的单词里基本上都把整个段落的内容概括了。

由此可以将没有意义,但出现频率很高的单词过滤掉,这类词在NLP自然语言处理里称之为stop words终止词,过滤的时候在上述代码中循环处理添加进列表的时候就可以判断,如果是终止词,就不添加,即:

def mapper(filename):words_list=[]list_stopWords=['the','a','and','or','is', 'are','to','in','at','by','of','but']#常见终止词列表with open(filename,'r') as f:content=f.readlines()for para in content:para=para.split('。')para0=para[0].split('.')for item in para0:words=item.split(' ')for word in words:if word.isalpha()==False:continueif word in list_stopWords: continue           #过滤终止词words_list.append(word.lower()) return words_list

再来看词频统计结果:

'miners': 5, 'underground': 4, 'rescuers': 3, 'located': 3, 'trapped': 3, 'coal': 3, 'were': 3, 'have': 2, 'mine': 2, 'sichuan': 2, 'the': 2, 'shaft': 2, 'reach': 2, 'water': 2, 'workers': 2, 'chengdu': 1, 'flooded': 1, 'southwest': 1, 'local': 1, 'authorities': 1, 'said': 1, 'sunday': 1, 'clearing': 1, 'drilling': 1, 'deep': 1, 'hole': 1, 'they': 1, 'also': 1, 'trying': 1, 'pump': 1, 'block': 1, 'bid': 1, 'prevent': 1, 'rising': 1, 'levels': 1, 'sending': 1, 'more': 1, 'oxygen': 1, 'down': 1, 'accident': 1, 'occurred': 1, 'pm': 1, 'saturday': 1, 'shanmushu': 1, 'owned': 1, 'industry':1

这样再来看,就明白了这个新闻里说的就是,四川挖煤矿的工人被困在井下,救援者进行施救。所以词频统计对理解段落含义很有意义。

最后再来一个词云展示,也就是将上述词频统计里出现的词用一种图来表示出来,比较直观。具体实现的时候需要先安装一个wordcloud词云第三方库,matplotlib绘图库,然后先设置绘图背景,然后将词频统计结果放置到背景上呈现效果。整个代码组织如下:

from wordcloud import WordCloud, STOPWORDS  #生成词云、通用词
import matplotlib.pyplot as plt  # 在线显示def mapper(filename):words_list=[]list_stopWords=['the','a','and','or','is', 'are','to','in','at','by','of','but']#常见终止词列表with open(filename,'r') as f:content=f.readlines()for para in content:para=para.split('。')para0=para[0].split('.')for item in para0:words=item.split(' ')for word in words:if word.isalpha()==False:continueif word in list_stopWords: continue           #过滤终止词words_list.append(word.lower()) return words_listdef reduce(words):words_dict={}for word in words:if word in words_dict:words_dict[word]+=1else:words_dict[word]=1words_dict=sorted(words_dict.items(),key=lambda x:x[1],reverse=True)return dict(words_dict)filename="new.txt"     #文件资源位置
wordlist=mapper(filename)   #获取单词列表
wordCount=reduce(wordlist)  #对词频进行统计#准备绘制词云图
wc = WordCloud(background_color="white",width=600, height=400, margin=5)  #准备一个背景
wc.generate_from_frequencies(wordCount)                                  #根据词频统计结果产生词云
plt.imshow(wc)                            #显示出来
plt.axis("off")
plt.show()

执行后效果如下:

词频统计思路就是如上分步骤所述,但具体到每篇文章,由于文章的格式、标准等都不一样,所以还需要具体问题去分析,需要哪些步骤来实现。

上述的词频统计是自然语言处理的一个最基本阶段,即Tokenization标识化。这部分任务在nltk自然语言处理库里调用其word_tokenize方法就可以完成。用法为:

import nltk
text="I love China and I was born in Hubei Province"
tokens=nltk.word_tokenize(text)
print(tokens)

另外还可以使用python自带的collections库里的counter函数,直接获得词频统计结果。我们上述的代码实际上就是将这个词频统计Counter函数进行了详细解析。例如:

import collections
text = "I love China and I was born in Hubei Province"
words=collections.Counter(text.split(' '))
print(words)

打印结果为:

Counter({'I': 2, 'love': 1, 'China': 1, 'and': 1, 'was': 1, 'born': 1, 'in': 1, 'Hubei': 1, 'Province': 1})

10行代码读懂红楼梦

中文文章词频统计任务相对英文要稍微复杂一些,因为英文单词与单词之间天然就用空格空隔开,所以很容易处理;但中文就不一样了,一段中文话里每个字与每个字之间没有天然的分割标记,而且还有含义的理解。比如“我看他们在跳舞”这句话,“我”是一个词,“看”是一个词,“他们”是一个词,“在”是一个词,“跳舞”是一个词。也就是一个词可能是一个字,也有可能是多个字构成。这样在处理的时候就麻烦了。如何确定是一个词语呢?

这里就需要引入前人所做的工作,把所有词语都统计好了,形成一个字典库,名称叫结巴分词,直接从cmd窗口使用pip install jieba命令就可以下载到本地:

pip install jieba

为了了解结巴分词模块的用法,可以去python安装目录下找到site-packages里的jieba文件夹,如下:

使用文本编辑器打开其中的_init_.py文件,查看其源代码,定位其中常用的cut方法,即分词方法。

 def cut(self, sentence, cut_all=False, HMM=True):'''The main function that segments an entire sentence that containsChinese characters into seperated words.Parameter:- sentence: The str(unicode) to be segmented.- cut_all: Model type. True for full pattern, False for accurate pattern.- HMM: Whether to use the Hidden Markov Model.'''sentence = strdecode(sentence)if cut_all:re_han = re_han_cut_allre_skip = re_skip_cut_allelse:re_han = re_han_defaultre_skip = re_skip_defaultif cut_all:cut_block = self.__cut_allelif HMM:cut_block = self.__cut_DAGelse:cut_block = self.__cut_DAG_NO_HMMblocks = re_han.split(sentence)for blk in blocks:if not blk:continueif re_han.match(blk):for word in cut_block(blk):yield wordelse:tmp = re_skip.split(blk)for x in tmp:if re_skip.match(x):yield xelif not cut_all:for xx in x:yield xxelse:yield xdef cut_for_search(self, sentence, HMM=True):"""Finer segmentation for search engines."""words = self.cut(sentence, HMM=HMM)for w in words:if len(w) > 2:for i in xrange(len(w) - 1):gram2 = w[i:i + 2]if self.FREQ.get(gram2):yield gram2if len(w) > 3:for i in xrange(len(w) - 2):gram3 = w[i:i + 3]if self.FREQ.get(gram3):yield gram3yield w

代码中有关cut方法的参数说明:cut_all: 如果设置为true则为全模式分词,如果为false,就为精确分词,如果使用HMM就使用隐层马尔科夫模型。具体效果如何,使用代码来实践看看:

import jieba
text="我在看他们跳舞,我心里高兴得不得了。有时候我也想也许我也可以这样随便跳起舞来"
#设置参数cut_all=True,即全模式分词
word_sep1=list(jieba.cut(text,cut_all=True))
print("全模式分词效果为:",word_sep1)
#设置参数cut_all=False,即精确模式分词
word_sep2=list(jieba.cut(text,cut_all=False))
print("精确模式分词效果为:",word_sep2)

运行后结果返回列表结果如下:

全模式分词效果为 :['我', '在', '看', '他们', '跳舞', '', '', '我心', '心里', '高兴', '得', '不得', '不得了', '', '', '有时', '有时候', '时候', '我', '也', '想', '也许', '我', '也', '可以', '这样', '随便', '跳起', '起舞', '来']

精确模式分词效果为: ['我', '在', '看', '他们', '跳舞', ',', '我', '心里', '高兴', '得', '不得了', '。', '有时候', '我', '也', '想', '也许', '我', '也', '可以', '这样', '随便', '跳', '起舞', '来']

对比而言,精确分词更为准确,全模式分词还有词的联想效果。

有了这个非常好用的分词方法,那对于大段中文文章的词频统计过程就与上述的英文文章类似了。也是分:首先分词处理,获得词语的列表,然后进行map操作,构建字典,每个词语出现过,就给次数1,最后再进行reduce操作,将相同词语出现的次数相加,获得出现频率结果。

下面我对红楼梦相关章节进行分词处理。这个难度还是比较大的,主要是红楼梦属于古典小说,有许多文言文表达,而不是白话文。所以分词效果并不是非常准确。不过对于练习已经足够有吸引力了。

第一步,从网上下载红楼梦小说txt文本,保存成一个文本文件。

第二步,开始在python中编写代码,首先读取这个文本文件,获得红楼梦中文文本。并使用分词结果构建一个字典,字典内容为<词语,次数1>。由于全部回数的文本很长,在练习时可以选择其中一部分来进行测试。代码参考如下:

import jieba#定义函数mapper,用于构建字典
def mapper(file):word_sep=[]word_map={}punctuation=['?','!',',','。',';',':','“','”','n','u3000','(',')']stopwords=["之","的","一","他","她","我","我们","可以","你","里","去","来","那","在","上","下"]with open(file,'r') as f:text=f.readlines()    for i in range(50):words=list(jieba.cut(text[i],cut_all=False))for word in words:if word in punctuation:continue   #去除标点符号if word in stopwords:continue     #去除终止词word_sep.append(word)for word in word_sep:word_map[word]=1return word_map#主函数
if __name__=="__main__":file='红楼梦.txt'print(mapper(file))

在这一步中使用了标点符号和终止词,当分词后的字符是标点符号和终止词时,就不加入字典。不过这里终止词是我自己构建的列表,内容相对较少。这块可以自行增加。

运行上述代码后就可以获得如下结果(这里受限篇幅仅显示部分结果):

{'甄士隐': 1, '梦幻': 1, '识通灵': 1, '贾雨村': 1, '风尘': 1, '怀': 1, '闺秀': 1, '1': 1, '列位': 1, '看官': 1, '道': 1, '此书': 1, '从何而来': 1, '说起': 1, '根由': 1, '虽近': 1, '荒唐': 1, '细': 1, '按': 1, '则': 1, '深有': 1, '趣味': 1, '待': 1, '将': 1, '此': 1, '来历': 1, '注明': 1, '方使': 1, '阅者': 1, '了然': 1, '不惑': 1, '原来': 1, '女娲': 1, '氏': 1, '炼石补天': 1, '时': 1, '于': 1, '大': 1, '荒山': 1, '无稽': 1, '崖': 1, '炼成': 1, '高经': 1, '十二': 1, '丈': 1, '、': 1, '方经': 1, '二十四丈': 1, '顽石': 1, '三万': 1, '六千五百': 1, '零': 1, '一块': 1, '娲': 1, '皇氏': 1, '只用': 1, '了': 1, '块': 1, '只': 1, '单单': 1, '剩': 1, '未': 1, '用': 1, '便弃': 1, '此山': 1, '青埂峰': 1, '谁知': 1, '此石': 1, '自经': 1, '煅炼': 1, '之后': 1, '灵性': 1, '已通': 1, '因见': 1, '众': 1, '石俱得': 1, '补天': 1, '独': 1, '自己': 1, '无材': 1, '不堪': 1, '入选': 1, '遂': 1, '自怨': 1, '自叹': 1, '日夜': 1, '悲号': 1, '惭愧': 1, '一日': 1, '正当': 1, '嗟悼': 1, '之际': 1, '俄见': 1, '一僧': 1, '一道': 1, '远远': 1, '而': 1, '生得': 1, '骨格': 1, '不凡': 1, '丰神': 1, '迥别': 1, '说说笑笑': 1, '至峰': 1, '坐于': 1, '石边': 1, '高谈': 1, '快论': 1, '先是': 1, '说些': 1, '云山': 1, '雾海': 1, '神仙': 1, '玄幻': 1, '之事': 1, '后': 1, '便': 1, '说': 1, '到': 1, '红尘': 1, '中': 1, '荣华富贵': 1, '听': 1, '不觉': 1, '打动': 1, '凡心': 1, '也': 1, '想要': 1, '人间': 1, '享一享': 1, '这': 1, '但': 1, '自恨': 1, '粗蠢': 1, '不得已': 1}

第三步,有了上述的词语字典后,就可以进行词频统计了。此时增加一个reducer函数,专门用于处理统计。

def reducer(word_dict):word_freq={}for key in word_dict:        if key in word_freq:word_freq[key]+=1            else:word_freq[key]=1word_freq=sorted(word_freq.items(),key=lambda x:x[1],reverse=True)return dict(word_freq) 

输出词频统计结果,如下示例:

文字出现的频率为: {'道': 8, '弟子': 6, '一块': 4, '便': 4, '到': 4, '红尘': 4, '听': 4, '不知': 4, '补天': 3, '说': 3, '不能': 3, '却': 3, '如此': 3, '自然': 3, '则': 2, '将': 2, '此': 2, '不惑': 2, '原来': 2, '时': 2, '荒山': 2, '无稽': 2, '崖': 2, '三万': 2, '六千五百': 2, '只': 2, '青埂峰': 2, '此石': 2, '无材': 2, '一日': 2, '一僧': 2, '一道': 2, '而': 2, '荣华富贵': 2, '凡心': 2, '但': 2, '粗蠢': 2, '繁华': 2, '富贵': 2, '善哉': 2, '好': 2, '这石': 2, '再': 2, '那僧': 2, '助': 2, '还': 2, '石头': 2, '个': 2, '携': 2, '空空': 2, '道人': 2, '甄士隐': 1, '梦幻': 1, '识通灵': 1, '贾雨村': 1, '风尘': 1, '怀': 1, '闺秀': 1, '1': 1, '列位': 1, '看官': 1, '此书': 1, '从何而来': 1, '说起': 1, '根由': 1, '虽近': 1, '荒唐': 1, '细': 1, '按': 1, '深有': 1, '趣味': 1, '待': 1, '来历': 1, '注明': 1, '方使': 1, '阅者': 1, '了然': 1, '女娲': 1, '氏': 1, '炼石补天': 1, '于': 1, '大': 1, '炼成': 1, '高经': 1, '十二': 1, '丈': 1, '方经': 1, '二十四丈': 1, '顽石': 1, '零': 1, '娲': 1, '皇氏': 1, '只用': 1, '块': 1, '单单': 1, '剩': 1, '未': 1, '用': 1, '便弃': 1, '此山': 1, '谁知': 1, '自经': 1, '煅炼': 1, '之后': 1, '灵性': 1, '已通': 1, '因见': 1, '众': 1, '石俱得': 1, '独': 1, '自己': 1, '不堪': 1, '入选': 1, '遂': 1, '自怨': 1, '自叹': 1, '日夜': 1, '悲号': 1, '惭愧':1}

细看统计结果,里面出现许多一个字的词语,一般情况下中文单个文字表达的意思还是很有限的,多以词组的形式来表示含义。因此需要将单个文字从词语统计中剔除。

另外为了统计结果更直观,代码中也增加词云库,使用词云来显示词频统计的结果。词云显示的时候由于是汉字,所以需要增加汉字字库。即给定font_path,代码中直接调用windows系统的字体库中的宋体。

wc = WordCloud(background_color="white",width=600, height=400, margin=5,font_path="C:/Windows/Fonts/simsun.ttc")  

将上述三步合起来,代码整体组织如下:

import jieba
from wordcloud import WordCloud, STOPWORDS  #生成词云、通用词
import matplotlib.pyplot as plt  # 在线显示#定义函数mapper,用于构建词语列表
def mapper(file):word_sep=[]word_map={}punctuation=['?','!',',','。',';',':','“','”','’','‘','n','u3000','(',')','、']stopwords=["之","的","一","他","她","我","我们","可以","你","里","去","来","那","在","上","下","了","又","是","这","着","也","人",'不','有']with open(file,'r') as f:text=f.readlines()    for i in range(50):                      #取前50列表测试words=list(jieba.cut(text[i],cut_all=False))   #结巴分词for word in words:if word in punctuation:continue         #去除标点符号if word in stopwords:continue           #去除终止词if len(word)<2:continue                 #去除单个字word_sep.append(word)                   #将分好的词语添加到空列表return word_sep#定义函数,用于词频统计
def reducer(word_dict):word_freq={}for key in word_dict:        if key in word_freq:word_freq[key]+=1            else:word_freq[key]=1word_freq=sorted(word_freq.items(),key=lambda x:x[1],reverse=True)return dict(word_freq)       #主函数
if __name__=="__main__":file='红楼梦.txt'word_dict=mapper(file)    word_freq=reducer(word_dict)#print("文字出现的频率为:",word_freq)wc = WordCloud(background_color="white",width=600, height=400, margin=5,font_path="C:/Windows/Fonts/simsun.ttc")wc.generate_from_frequencies(word_freq)plt.imshow(wc)plt.axis("off")plt.show()

运行程序,获得如下词云图:

这个图云是对前几回的文本进行的统计,所以里面出现了雨村、士隐、道人、封肃、丫鬟、那僧、世人、弟子等较高出现的词语,基本上能够概括前几回的主要人物和事情。

如果把全部红楼梦的文字都拿进来,最后的词云图如下(效果与选择终止词有关):

再来对比整个红楼梦,这张词云图上出现的就是宝玉、贾母、王夫人、凤姐、姑娘、奶奶、黛玉、袭人、宝钗等红楼梦核心人物。

python split函数 空格_python上手--10行代码读懂红楼梦相关推荐

  1. 动手敲10行代码读懂Python

    最近在MOOC上自学Python课程,觉得老师的讲解通俗易懂,受益良多,也决定多动手记录学习的点点滴滴,督促自己快速进步. 自己动手敲了第一课的10行小代码,实现了简单的温度转换算法. #TempCo ...

  2. python split函数 空格_Python随笔29:Python基础编程练习题23~24

    注:本文所有代码均经过Python 3.7实际运行检验,保证其严谨性. Python编程 Python基础练习题23:求三角形斜边上的高 输入直角三角形两直角边a.b的值,输出斜边上的高,最后结果使用 ...

  3. python split函数 空格_最易懂的Python新手教程:从基础语法到代码详解

    导读:本文立足基础,讲解Python和PyCharm的安装,及Python最简单的语法基础和爬虫技术中所需的Python语法. 作者:罗攀 蒋仟 如需转载请联系华章科技 本文涉及的主要知识点如下: P ...

  4. python人脸识别代码_Python不用10行代码就可实现人脸识别,还可辨别真假,太棒了!...

    人脸识别技术大致由人脸检测和人脸识别两个环节组成.之所以要有人脸检测,不光是为了检测出照片上是否有人脸,更重要的是把照片中人脸无关的部分删掉,否则整张照片的像素都传给f(x)识别函数肯定就不可用了.人 ...

  5. python写的有道翻译代码_Python爬虫10行代码实现调用有道翻译,以及加入语音功能...

    版本1.0 有道翻译这个项目很多人做过,但这个版本可能是你看过最简洁的,代码10行.我们把它命名为'版本1.0',后续版本可以直接引用这个代码 代码展示:import requests import ...

  6. python画土拨鼠代码_Python 用10行代码教你画出太阳花

    (点击上方快速关注并设置为星标,一起学Python) 参考链接: https://www.cnblogs.com/asd516970982/p/10484000.html 用 Python 中的 tu ...

  7. 用python画满天星花朵_Python用27行代码绘制一幅满天星

    前言 每一个孩子都像星空中的一颗星星,散发着自己所特有的光芒照亮着整个夜空.今天就带大家用27行Python代码绘制一幅满天星吧. 全局设置 在绘制满天星的过程中要运用到turtle工具,它是Pyth ...

  8. python绘制像素图_Python用61行代码实现图片像素化的示例代码

    起因 看到网上的像素图片,感觉蛮有趣的,就打算用python一些PIL类库写一个. 实现思路 把一张图片分成多个块,每个块的颜色都等于这个色块中颜色最多的颜色,如下图. 这个图取2×2的像素为块的大小 ...

  9. python怎么判断真假_Python不超过10行代码就可实现人脸识别,教你辨别真假

    [[爱编程的南风]Python不超过10行代码就可实现人脸识别,教你辨别真假]http://toutiao.com/group/6518157903055045127/?iid=15906422033 ...

最新文章

  1. jsp 出现cannot be resolved to a type问题解决办法
  2. angular react_Angular 2 vs React:将会有鲜血
  3. jsp 调用java_jsp中调用java代码小结
  4. 【Apache】指定 某一个URL 并进行 Auth 认证
  5. “百度智能云”下,群星璀璨,照亮百度世界2020
  6. gRPC学习记录(四)--官方Demo
  7. [Leedcode][JAVA][面试题 16.18][模式匹配][字符串][枚举]
  8. springboot springmvc mybatis_12道重点的Spring Boot面试题,帮你整理好了!
  9. BP算法是从天上掉下来的吗?
  10. fastjson 添加key value_FastJson迁移至Jackson
  11. JAVA反射-面试题
  12. java编程艺术 高永强_Shardingsphere can not initialize xaTransaction问题
  13. UltraEdit编辑器中文乱码问题解决
  14. 开发一种提供医学药学常用公式图片的文档编辑器插件
  15. 人工智能顶级会议与国际期刊总结
  16. 李宏毅机器学习01机器学习介绍
  17. oracle ipac,Oracle VM VritualBOX安装Centos详解与注意事项
  18. 7 种模型加权集成方法
  19. centos解压与压缩zip格式文件
  20. 计算机基础-二元一次方程组的概念及基本解法

热门文章

  1. npm如何设置淘宝镜像
  2. 取某个单元格的值_vba中如何进行单元格复制,Copy方法使用介绍,一定要学
  3. 曲曲直直线条图计算机教案,【曲曲直直的美术画】_美术教案第三课:曲曲直直(三年级美术下册教案)——小学美术...
  4. 前后两组结构相同的数据进行比较,找出新增的,需要删除的,原来存在的
  5. BugkuCTF-MISC题多方法解决
  6. mysql数据应用从入门_MYSQL数据库应用从入门到精通----读书笔记
  7. python history函数_python的history_n 和history函数 获取的成交量和持仓量出现翻倍
  8. 复旦计算机考研复试要口试吗,2017复旦大学考研复试:英语口语面试常见问题汇总...
  9. oracle rollup分组没有数据时为0_数据库周刊19│GBASE适配鲲鹏;MySQL窗口函数;OGG双向数据同步……...
  10. matlab chan算法定位,MATLAB实现基于Chan氏算法的三维TDOA定位