python词频统计并按词频排序
下篇:python中文词频统计
这篇博客用来记录一下自己学习用python做词频统计的过程,分别用字典和第三方库来完成词频统计
一、用字典统计英文词频,所用文本《THE CATCHER IN THE RYE 》(麦田里的守望者)
链接:link
提取码:jz7p
涉及的第三方库及其在程序中的用途如下:
import string #去除英文标点符号
from nltk.corpus import stopwords #去掉一些停用词
这里说下停用词,所谓停用词,多是一些出现频繁但实际意义不大或是对文本分析帮助不大的词汇,如英文里的a,an,that 中文里的“的”、“是”等词,下面是一些语言的常用停用词库链接:[link](https://www.ranks.nl/stopwords)
第三方库的使用将使我们的词频统计工作变得更为简单且细致,在接下来的用到时再细说。现在,让我们捋一捋词频统计的流程,显然,我们首先要拿到文本资源,并将需要处理的字符从文本中读出来:
f = open('E:\Python_code\Big_data\homework4\maitian.txt')
text = f.read()
f.close() #用open()打开的文件记得要关闭
#或者用下面这种方式,python会自动帮我们关闭文件
with open('E:\Python_code\Big_data\homework4\maitian.txt') as f:
text= f.read()
接着,我们需要对得到的text字符串做一些处理,当然我们也可以简单粗暴地直接用split()函数对text进行切分,但是这样文本中的标点符号及单词的大小写问题就没有得到处理,影响统计结果。string.punctuation包含了要去除的英文符号,这是第三方库的便捷点,让我们不必手动将一个个标点打出来
stop_words = stopwords.words('english') #要去掉的停用词
ls = list(string.punctuation) #要去除的英文标点符号,包含!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
text = text.lower() #统一为小写格式
for i in ls: #将标点符号替换为空格
text = text.replace(i," ")
lis = text.split() #切分单词
split()函数定义如下,sep参数是分隔符,默认对空格符,回车符,换行符等空格进行切分,maxsplit参数是最大切分次数,一般不需要指定,函数返回一个切分后的字符串列表
def split(self, sep: str , maxsplit: SupportsIndex = …)
这样,我们就得到了切分后的单词列表,可以用切片的方法看一下里面的单词 print(lis[:20])
[‘the’, ‘catcher’, ‘in’, ‘the’, ‘rye’, ‘by’, ‘j’, ‘d’, ‘salinger’, ‘to’, ‘my’, ‘mother’, ‘1’, ‘if’, ‘you’, ‘really’, ‘want’, ‘to’, ‘hear’, ‘about’]
可以看到,列表中还有单个的字母和数字以及一些停用词,这对我们的词频统计工作是不利的,应该想办法去掉,当然,处理方式是多种多样的,我这里就简单粗暴一点,把长度为1的字符都去掉,咋看这步似乎包括了去标点符号。但如果你不想去掉所有长度为1的字符,那么单独去掉标点符号还是有必要的。
counts= {}
for i in lis: #统计词频 ,不统计长度为1的词
if(len(i) >1):
counts[i] = counts.get(i,0)+1
for word in stop_words: #去掉停用词
counts.pop(word,0)
简单介绍下字典的两个方法,get()方法用来找与键(key)对应的值的,找到了就返回对应的值,没找到就返回默认值(default), pop()方法用来移除字典中某一键值对,如果有与(key)对应的值就将键值对移除并返回键对应的值(value),没有就返回默认值(default)
get(self, key , default )
pop(self, key, default)
这样,我们就得到了一个词频字典,可以直接打印看里面的内容,但是内容太多,并不建议这么做,我们对其按值(也就是单词出现的频数)进行排序,将结果赋给一个列表,然后看一下列表中的前20个元素:
这里简单介绍一下sorted函数,这是一个python内置函数,
sorted(iterable, cmp=None, key=None, reverse=False)
iterable – 可迭代对象。
cmp – 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0,一般不要指定。
key --指定排序依据,下面的用法就是按照传入元组对的第二个值进行排序(按频数排序)key.items()返回键值组成的元组对,lambda函数则取传入元组对的第二个值作为返回值。
reverse – 指定排序规则,为时True 降序排列, False 升序(默认)。
ls1 = sorted(counts.items(),key=lambda x:x[1],reverse=True)
print(ls1[:20])
[(‘said’, 705), (‘like’, 403), (‘old’, 397), (‘know’, 316), (‘one’, 281), (‘get’, 261), (‘got’, 257), (‘goddam’, 245), (‘go’, 245), (‘right’, 244), (‘around’, 238), (‘even’, 238), (‘hell’, 234), (‘really’, 228), (‘something’, 220), (‘could’, 208), (‘anything’, 205), (‘though’, 191), (‘mean’, 183), (‘time’, 183)]
另外,还可以对排序结果做些改进,如将上面的"get"和"got"当成一个词处理等
下面贴一份完整代码
import string
from nltk.corpus import stopwords
f = open('E:\Python_code\Big_data\homework4\maitian.txt')
text = f.read()
f.close()
stop_words = stopwords.words('english') #要去掉的停用词
ls = list(string.punctuation) #要去除的英文标点符号
text = text.lower() #统一为小写格式
for i in ls: #将标点符号替换为空格
text = text.replace(i," ")
lis = text.split()
counts= {}
for i in lis: #统计词频 ,不统计长度为1的词
if(len(i) >1):
counts[i] = counts.get(i,0)+1
for word in stop_words: #去掉停用词
counts.pop(word,0)
ls1 = sorted(counts.items(),key=lambda x:x[1],reverse=True) #词频排序
print(ls1[:20])
二、用collections.Counter()统计词频
接下来介绍使用第三方库完成词频统计的方法,整体的逻辑其实和上面差不多,只是使用了第三方库而已,这样做的好处是可以减少代码量,提高程序运行效率,另外有许多第三方库都可以实现词频统计功能,这里仅介绍比较常见的两种
import collections
import string
from nltk.corpus import stopwords
f = open('E:\Python_code\Big_data\homework4\maitian.txt')
text = f.read()
f.close()
stop_words = stopwords.words('english') #要去掉的停用词
ls = list(string.punctuation) #要去除的英文标点符号
text = text.lower() #统一为小写格式
for i in ls: #将标点符号替换为空格
text = text.replace(i," ")
lis = text.split()
cl = collections.Counter(lis)#词频统计
for i in stop_words: #去掉停用词
cl.pop(i,0)
print(cl.most_common(20))
三、用pandas库统计词频
import pandas as pd
import string
from nltk.corpus import stopwords
f = open('E:\Python_code\Big_data\homework4\maitian.txt')
text = f.read()
f.close()
stop_words = stopwords.words('english') #要去掉的停用词
ls = list(string.punctuation) #要去除的英文标点符号
text = text.lower() #统一为小写格式
for i in ls: #将标点符号替换为空格
text = text.replace(i," ")
lis = text.split()
ds = pd.Series(lis).value_counts()
for i in stop_words:
try: #处理找不到元素i时pop()方法可能出现的错误
ds.pop(i)
except:
continue #没有i这个词,跳过本次,继续下一个词
print(ds[:20])
贴个测试图:
python词频统计并按词频排序_python编写:一个单词的“排名”是它在单词列表中按频率排序的位置:最常见的词-CSDN博客
python jieba分词及中文词频统计_python jieba一共有多少个词-CSDN博客
一、jieba库简介
jieba是Python中一个重要的第三方中文分词函数库,需要通过
pip指令安装,顺便一说,使用-i 参数指定国内镜像源,速度更快
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jieba
jieba分词的三种常见模式如下
* 精确模式,尝试将句子最精确地切开,适合文本分析,不过精确模式分词速度不尽人意
* 全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义问题;
* 搜索引擎模式,在精确模式的基础上,对长词再次切分,适合用于搜索引擎分词。
简单介绍下jieba库的几个常用方法
jieba.lcut(s) 精确模式,返回一个列表类型,一般分词就用这个方法
jieba.lcut(s, cut_all=True) 全模式,返回一个列表类型,
jieba.lcut_for_search(s) 搜索引擎模式,返回一个列表类型
下面简单看下三个方法的效果
>>> import jieba
>>> jieba.lcut("青年一代是充满朝气、生机勃勃的")#精确模式
['青年一代', '是', '充满', '朝气', '、', '生机勃勃', '的']
>>> jieba.lcut("青年一代是充满朝气、生机勃勃的",cut_all=True)#全模式
['青年', '青年一代', '一代', '是', '充满', '满朝', '朝气', '、', '生机', '生机勃勃', '勃勃', '勃勃的']
>>> jieba.lcut_for_search("青年一代是充满朝气、生机勃勃的")#搜索引擎模式
['青年', '一代', '青年一代', '是', '充满', '朝气', '、', '生机', '勃勃', '生机勃勃', '的']
>>>
可以看到,精确模式对句子的切分最为准确,适合用来做文章词频统计,其它两个模式各有侧重,全模式会提供尽可能多的词,但不能解决歧义,搜索引擎模式切分出来的词适合作为搜索引擎的索引或关键字。
接下用,我们尝试用精确模式来对《水浒传》进行切分,并统计切分后的词频。
二、一些准备工作
同样的,这里也需要用到停用词表处理停用词并用相关第三方库解决中文标点符号问题
中文标点可以直接用zhon库(不是自带的库,需要手动安装)
import zhon.hanzi
punc = zhon.hanzi.punctuation #要去除的中文标点符号
print(punc)
#包括"#$%&'()*+,-/:;<=>@[\]^_`{|}~⦅⦆「」、 、〃〈〉《》「」『』【】〔〕〖〗〘〙〚〛〜〝〞〟〰〾〿–—‘’‛“”„‟…‧﹏﹑﹔·!?。。
这样,中文标点的问题解决了,但是,我上篇中用过的nltk库的停用词库里并没有中文停用词表,于是我就在网上重新找了一个并把它加到了nltk库的停用词表库里去,这样它就有中文停用词表了,我可真是机灵.jpg
当然这里其实也可以直接将停用词表保存为.txt文档,用的时候直接读入就行,下面介绍一下上述两种操作
某大佬在github分享的停用词表
我这里用的百度停用词表,但是尴尬的是它对我选择文本的词语排除效果好像不是很好…
一、将百度停用词表加入nltk库的停用词库中
①首先将百度停用词表复制(下载)下来,保存为.txt文档,注意文档格式,必须是每行一个词(字)
②接下来,找到nltk的停用词库路径,一般在python文件夹的lib中找,参考路径如下,python3.9.7\Lib\nltk_data\corpora\stopwords
你可以在lib里直接搜索stopwords,不过前提是你安装了nltk库,当然lib下可能有几个stopwords,不要弄错了,是nltk目录下的那个
③将我们前面提到的.txt文档复制到stopwords里,把后缀名.txt去掉就行
大功告成,接下来试试添加的停用词表能成功加载不
>>> from nltk.corpus import stopwords
>>> baidu_stopwords = stopwords.words("baidu_stopwords")
>>> print(baidu_stopwords[:100])
['--', '?', '“', '”', '》', '--', 'able', 'about', 'above', 'according', 'accordingly', 'across', 'actually', 'after', 'afterwards', 'again', 'against', "ain't", 'all', 'allow', 'allows', 'almost', 'alone', 'along', 'already', 'also', 'although', 'always', 'am', 'among', 'amongst', 'an', 'and', 'another', 'any', 'anybody', 'anyhow', 'anyone', 'anything', 'anyway', 'anyways', 'anywhere', 'apart', 'appear', 'appreciate', 'appropriate', 'are', "aren't", 'around', 'as', "a's", 'aside', 'ask', 'asking', 'associated', 'at', 'available', 'away', 'awfully', 'be', 'became', 'because', 'become', 'becomes', 'becoming', 'been', 'before', 'beforehand', 'behind', 'being', 'believe', 'below', 'beside', 'besides', 'best', 'better', 'between', 'beyond', 'both', 'brief', 'but', 'by', 'came', 'can', 'cannot', 'cant', "can't", 'cause', 'causes', 'certain', 'certainly', 'changes', 'clearly', "c'mon", 'co', 'com', 'come', 'comes', 'concerning', 'consequently']
>>> print(baidu_stopwords[-100:])
['起', '起来', '起见', '趁', '趁着', '越是', '跟', '转动', '转变', '转贴', '较', '较之', '边', '达到', '迅速', '过', '过去', '过来', '运用', '还是', '还有', '这', '这个', '这么', '这么些', '这么样', '这么点儿', '这些', '这会儿', '这儿', '这就是说', '这时', '这样', '这点', '这种', '这边', '这里', '这麽', '进入', '进步', '进而', '进行', '连', '连同', '适应', '适当', '适用', '逐步', '逐渐', '通常', '通过', '造成', '遇到', '遭到', '避免', '那', '那个', '那么', '那么些', '那么样', '那些', '那会儿', '那儿', '那时', '那样', '那边', '那里', '那麽', '部分', '鄙人', '采取', '里面', '重大', '重新', '重要', '鉴于', '问题', '防止', '阿', '附近', '限制', '除', '除了', '除此之外', '除非', '随', '随着', '随著', '集中', '需要', '非但', '非常', '非徒', '靠', '顺', '顺着', '首先', '高兴', '是不是', '说说']
>>>
很好,加载成功了,说明我们成功给nltk库加上了中文停用词表,其实学会了这个操作后我们可以根据自己的需求定义自己的“停用词表”,将标点符号,停用词等放到一个文件中,这样用的时候直接导入nltk库,不需要导入其它库了
二、将百度停用词表保存为.txt文件,需要用的时候读取
with open('E:\Python_code\\blog\\baidu_stopwords.txt',encoding="utf-8") as fp:
text = fp.read()
print(text[:100],text[-100:])
三、中文词频统计
整个处理流程大致和上篇的英文词频统计差不多,主要就这几步:
*读入文档
*分词
*去掉标点及停用词
*统计词频
*排序
我这里不统计长度为1的词,所以去标点符号这步可省略,另外使用第三方库可以更快捷地统计词频,往往还集成了排序功能。
import jieba
import zhon.hanzi
from nltk.corpus import stopwords
punc = zhon.hanzi.punctuation #要去除的中文标点符号
baidu_stopwords = stopwords.words('baidu_stopwords') #导入停用词表
#读入文件
with open('E:\Python_code\Big_data\homework4\水浒传.txt',encoding="utf-8") as fp:
text = fp.read()
ls = jieba.lcut(text)#分词
#统计词频
counts= {}
for i in ls:
if len(i)>1:
counts[i] = counts.get(i,0)+1
#去标点(由于我这里不统计长度为1的词,去标点这步可省略)
# for p in punc:
# counts.pop(p,0)
for word in baidu_stopwords: #去掉停用词
counts.pop(word,0)
ls1 = sorted(counts.items(),key=lambda x:x[1],reverse=True) #词频排序
print(ls1[:20])
同上篇方法,我们也可借助第三方库完成词频统计
借助collections库
import jieba
import zhon.hanzi
from nltk.corpus import stopwords
import collections
punc = zhon.hanzi.punctuation #要去除的中文标点符号
baidu_stopwords = stopwords.words('baidu_stopwords') #导入停用词表
#读入文件
with open('E:\Python_code\Big_data\homework4\水浒传.txt',encoding="utf-8") as fp:
text = fp.read()
ls = jieba.lcut(text)
#去掉长度为1的词,包括标点
newls = []
for i in ls:
if len(i)>1:
newls.append(i)
#统计词频
counts = collections.Counter(newls)
for word in baidu_stopwords: #去掉停用词
counts.pop(word,0)
print(counts.most_common(20))
借助pandas库
import jieba
import zhon.hanzi
from nltk.corpus import stopwords
import pandas as pd
punc = zhon.hanzi.punctuation #要去除的中文标点符号
baidu_stopwords = stopwords.words('baidu_stopwords') #导入停用词表
#读入文件
with open('E:\Python_code\Big_data\homework4\水浒传.txt',encoding="utf-8") as fp:
text = fp.read()
ls = jieba.lcut(text)
#去掉长度为1的词,包括标点
newls = []
for i in ls:
if len(i)>1:
newls.append(i)
#统计词频
ds = pd.Series(newls).value_counts()
for i in baidu_stopwords:
try: #处理找不到元素i时pop()方法可能出现的错误
ds.pop(i)
except:
continue #没有i这个词,跳过本次,继续下一个词
print(ds[:20])
贴个测试结果
四、jieba自定义分词、词性分析
jieba支持自定义分词器,可以进行词性标注,但是不能保证所有词都被标注而且分析速度比较慢,这里只介绍一个例子,下面用自定义分词器对《“十四五”信息通信行业发展规划》解读做下词性分析
词性表
标记 | 词性 | 描述 |
---|---|---|
Ag | 形语素 | 形容词性语素。形容词代码为 a,语素代码g前面置以A。 a 形容词 取英语形容词 adjective的第1个字母。 |
ad | 副形词 | 直接作状语的形容词。形容词代码 a和副词代码d并在一起。 |
an | 名形词 | 具有名词功能的形容词。形容词代码 a和名词代码n并在一起。 |
b | 区别词 | 取汉字“别”的声母。 |
c | 连词 | 取英语连词 conjunction的第1个字母。 |
dg 副语素 | 副词性语素 | 副词代码为 d,语素代码g前面置以D。 d 副词 取 adverb的第2个字母,因其第1个字母已用于形容词。 |
e | 叹词 | 取英语叹词 exclamation的第1个字母。 |
f | 方位词 | 取汉字“方” |
g | 语素 | 绝大多数语素都能作为合成词的“词根”,取汉字“根”的声母。 |
h | 前接成分 | 取英语 head的第1个字母。 |
i | 成语 | 取英语成语 idiom的第1个字母。 |
j | 简称略语 | 取汉字“简”的声母。 |
k | 后接成分 | |
l | 习用语 | 习用语尚未成为成语,有点“临时性”,取“临”的声母。 |
m | 数词 | 取英语 numeral的第3个字母,n,u已有他用。 |
Ng | 名语素 | 名词性语素。名词代码为 n,语素代码g前面置以N。 n 名词 取英语名词 noun的第1个字母。 |
nr | 人名 | 名词代码 n和“人(ren)”的声母并在一起。 |
ns | 地名 | 名词代码 n和处所词代码s并在一起。 |
nt | 机构团体 | “团”的声母为 t,名词代码n和t并在一起。 |
nz | 其他专名 | “专”的声母的第 1个字母为z,名词代码n和z并在一起。 |
o | 拟声词 | 取英语拟声词 onomatopoeia的第1个字母。 |
p | 介词 | 取英语介词 prepositional的第1个字母。 |
q | 量词 | 取英语 quantity的第1个字母。 |
r | 代词 | 取英语代词 pronoun的第2个字母,因p已用于介词。 |
s | 处所词 | 取英语 space的第1个字母。 |
tg | 时语素 | 时间词性语素。时间词代码为 t,在语素的代码g前面置以T。 t 时间词 取英语 time的第1个字母。 |
u | 助词 | 取英语助词 auxiliary |
vg | 动语素 | 动词性语素。动词代码为 v。在语素的代码g前面置以V。 v 动词 取英语动词 verb的第一个字母。 |
vd | 副动词 | 直接作状语的动词。动词和副词的代码并在一起。 |
vn | 名动词 | 指具有名词功能的动词。动词和名词的代码并在一起。 |
w | 标点符号 | |
x | 非语素字 | 非语素字只是一个符号,字母 x通常用于代表未知数、符号。 |
y | 语气词 | 取汉字“语”的声母。 |
z | 状态词 | 取汉字“状”的声母的前一个字母。 |
un | 未知词 | 不可识别词及用户自定义词组。取英文Unkonwn首两个字母。(非北大标准,CSW分词中定义) |
import jieba.posseg as pseg
with open('E:/Python_code/blog/通信行业规划.txt',encoding="utf-8") as f:
text = f.read()
wordit = pseg.cut(text) #自定义分词,返回一个可迭代类型
count_flag = {}
for word ,flag in wordit:
if flag not in count_flag.keys(): #如果没有flag键,就添加flag键,对应的值为一个空列表,每个键代表一种词性
count_flag[flag] = []
elif len(word)>1: #有对应的词性键,就将词加入到键对应的列表中,跳过长度为1的词
count_flag[flag].append(word)
print(count_flag)