我们这次需要解决的问题是在一篇文章中,哪一些词汇出现的最多,如何去做,我们考虑英文文本和中文的文本。
首先,我们先对哈姆雷特的英文文本进行统计词频。
1、获取文本并进行归一化
def gettext():
txt=open("hamlet.txt","r").read()
txt=txt.lower()
for ch in '!"#$%&()*+,-./:;<>=?@[\\]^_‘{|}~':
txt=txt.replace(ch," ")
return txt
txt=open(“hamlet.txt”,“r”).read()为读取名为hamlet.txt的文本,然后txt=txt.lower()的作用为将文档中的文本所有字母转换为小写,然后我们使用将所有特殊字符的列举方法把所有的特殊字符均改为空格,这样可以将文本中的所有词汇都分隔开来。
2、主函数部分
hamlettxt=gettext()
words=hamlettxt.split()
counts={}
for word in words:
counts[word]=counts.get(word,0)+1
items = list(counts.items())
items.sort(key=lambda x:x[1],reverse=True)
for i in range(10):
word,count=items[i]
print("{0:<10}{1:>5}".format(word,count))
words=hamlettxt.split()为将文本转化为列表类型,然后定义一个counts的字典类型,然后利用字典的处理方法counts[word]=counts.get(word,0)+1,意为若字典中存在word键,则对应的值加一,但若不存在word键,则原值为0,再加一。随后为了便于操作我们将字典类型转化为列表类型。然后进行items.sort(key=lambda x:x[1],reverse=True),利用sort函数进行对整体的排序,lambda表示对哪一列进行排序,reverse=True意为从大到小排序,系统默认的为从小到大排序。而信息保存在items中,最后我们利用for来得到出现次数最大的十个词汇,得到我们想得到的结果。
最终结果如下:
由此我们可以得到词频最大的十个词汇,the是最多的。
接下来我们来考虑中文的文本如何处理。
这里我们利用jieba库对其中文文本进行处理。希望得到三国演义中出场次数最多的人。
代码如下:
#三国演义
import jieba
txt = open("threekingdoms.txt","rb+").read()
words = jieba.lcut(txt)
counts = {}
for word in words:
if len(word) == 1:
continue
else:
counts[word] = counts.get(word,0)+1
items = list(counts.items())
items.sort(key=lambda x:x[1],reverse=True)
for i in range(15):
word,count = items[i]
print("{0:<10}{1:>5}".format(word,count))
我们可以看出,在对文本的归一化去噪方面思路与英文文本基本一致,而差别在于加入了words=jieba.lcut(txt)的使用,对文本进行中文分词处理,形成了一个有所有单词的列表类型。因为我们希望找出词汇,所以把所有长度为1的全部去除,然后利用字典类型得出每一个词汇的频次,方法与计算英文词频类似。后面的和英文词频一致。
最终我们运行结果为前15的词汇:
对于结果我们发现有很多问题,第一是有很多词汇是指的同一个人,比如云长和关公都指的是关羽;第二是出现了很多非人物的词汇。
接下来我们希望对代码进行优化,得到更好的结果。
1、对于同一个人不同名字的情况我们采用比较的方式,若出现更多的同义词,我们便在代码中再次补充即可。
for word in words:
if len(word) == 1:
continue
elif word=="诸葛亮" or word=="孔明曰":
rword="孔明"
elif word=="关公" or word=="云长":
rword="关羽"
elif word=="玄德" or word=="玄德曰":
rword="刘备"
elif word=="孟德" or word=="丞相":
rword="曹操"
else:
rword=word
counts[rword] = counts.get(rword,0)+1
即生成一个新的列表,此列表中不存在相同词义的情况。
2、对于不是人名的情况,我们构造出一个集合,我们不断地运行程序,在前几中挑出不是人名的词汇添加到这个集合中,我们把最终的列表的元素排除掉在这个集合中的元素即为我们希望得到的结果。
excludes={"将军","却说","荆州","二人","不可","不能","如此"}
...
for word in excludes:
del counts[word]
完整代码如下:
#三国演义字数统计代码改进
import jieba
txt = open("threekingdoms.txt","rb+").read()
excludes={"将军","却说","荆州","二人","不可","不能","如此"}
words = jieba.lcut(txt)
counts = {}
for word in words:
if len(word) == 1:
continue
elif word=="诸葛亮" or word=="孔明曰":
rword="孔明"
elif word=="关公" or word=="云长":
rword="关羽"
elif word=="玄德" or word=="玄德曰":
rword="刘备"
elif word=="孟德" or word=="丞相":
rword="曹操"
else:
rword=word
counts[rword] = counts.get(rword,0)+1
for word in excludes:
del counts[word]
items = list(counts.items())
items.sort(key=lambda x:x[1],reverse=True)
for i in range(10):
word,count = items[i]
print("{0:<10}{1:>5}".format(word,count))
最终结果为:
我们可以发现,曹操为出场次数最多的三国人物。