• 统计文本词频的几种方法(Python)


    目录

    1. 单句的词频统计

    2. 文章的词频统计

    方法一:运用集合去重方法

    方法二:运用字典统计

    方法三:使用计数器


    词频统计是自然语言处理的基本任务,针对一段句子、一篇文章或一组文章,统计文章中每个单词出现的次数,在此基础上发现文章的主题词、热词。

    1. 单句的词频统计

    思路:首先定义一个空字典my_dict,然后遍历文章(或句子),针对每个单词判断是否在字典my_dictkey中,不存在就将该单词当作my_dictkey,并设置对应的value值为1;若已存在,则将对应的value值+1。

    1. #统计单句中每个单词出现的次数
    2. news = "Xi, also general secretary of the Communist Party of China (CPC) Central Committee and chairman of the Central Military Commission, made the remarks while attending a voluntary tree-planting activity in the Chinese capital's southern district of Daxing."
    1. def couWord(news_list):
    2. ##定义计数函数 输入:句子的单词列表 输出:单词-次数 的字典
    3. my_dict = {} #空字典 来保存单词出现的次数
    4. for v in news_list:
    5. if my_dict.get(v):
    6. my_dict[v] += 1
    7. else:
    8. my_dict[v] = 1
    9. return my_dict
    10. print(couWord(news.split ()))

    输出

    {‘Xi,’: 1, ‘also’: 1, ‘general’: 1, ‘secretary’: 1, ‘of’: 4, ‘the’: 4, ‘Communist’: 1, ‘Party’: 1, ‘China’: 1, ‘(CPC)’: 1, ‘Central’: 2, ‘Committee’: 1, ‘and’: 1, ‘chairman’: 1, ‘Military’: 1, ‘Commission,’: 1, ‘made’: 1, ‘remarks’: 1, ‘while’: 1, ‘attending’: 1, ‘a’: 1, ‘voluntary’: 1, ‘tree-planting’: 1, ‘activity’: 1, ‘in’: 1, ‘Chinese’: 1, “capital’s”: 1, ‘southern’: 1, ‘district’: 1, ‘Daxing.’: 1}

    以上通过couWord方法实现了词频的统计,但是存在以下两个问题。

    (1)未去除stopword

    输出结果中保护’also’、‘and’、'in’等stopword(停止词),停止词语与文章主题关系不大,需要在词频统计等各类处理中将其过滤掉。

    (2)未根据出现次数进行排序

    根据每个单词出现次数进行排序后,可以直观而有效的发现文章主题词或热词。

    改进后的couWord函数如下:

    1. def couWord(news_list,word_list,N):
    2. #输入 文章单词的列表 停止词列表 输出:Top N的单词
    3. my_dict = {} #空字典 来保存单词出现的次数
    4. for v in news_list:
    5. if (v not in word_list): # 判断是否在停止词列表中
    6. if my_dict.get(v):
    7. my_dict[v] += 1
    8. else:
    9. my_dict[v] = 1
    10. topWord = sorted(zip(my_dict.values(),my_dict.keys()),reverse=True)[:N]
    11. return topWord

    加载英文停止词列表:

    1. stopPath = r'Data/stopword.txt'
    2. with open(stopPath,encoding = 'utf-8') as file:
    3.     word_list = file.read().split()      #通过read()返回一个字符串函数,再将其转换成列表
    4. print(couWord(news.split(),word_list,5)) 

    输出

    [(2, ‘Central’), (1, ‘voluntary’), (1, ‘tree-planting’), (1, ‘southern’), (1, ‘secretary’)]

    2. 文章的词频统计

    (1)单篇文章词频统计

    通过定义读取文章的函数,对其进行大小写转换等处理,形成输入文章的单词列表。

    https://python123.io/resources/pye/hamlet.txt

    以上为hamlet英文版文本的获取路径,下载完成后保存到工程路径下。

    使用open()函数打开hamlet.txt文件,并使用read()方法读取文件内容,将文本保存在txt变量中。

    1. def readFile(filePath):
    2. #输入: 文件路径 输出:字符串列表
    3. with open(filePath,encoding = 'utf-8') as file:
    4. txt = file.read().lower() #返回一个字符串,都是小写
    5. words = txt.split() #转换成列表
    6. return words
    7. filePath = r'Data/news/hamlet.txt'
    8. new_list = readFile(filePath) #读取文件
    9. print(couWord(new_list,word_list,5))

    接下来,我们需要对文本进行预处理,去除标点符号、分割成单词等。我们可以使用正则表达式来实现这一步骤。

    1. import re
    2. # 去除标点符号
    3. text = re.sub(r'[^\w\s]', '', text)
    4. # 分割成单词
    5. words = text.split()

    我们使用re.sub()函数和正则表达式[^\w\s]来去除标点符号,然后使用split()方法将文本分割成单词,并将结果保存在words列表中。

    或者:

    我们的文本中含有标点和字符的噪声数据,所以要进行数据的清洗,将文档全部处理为只有我们需要的字母类型(为方便操作,用空格替换噪声数据,将文档全部转化为小写字母)

    打开文件,进行读取,清洗数据,数据归档。

    1. def getText():
    2. txt = open("Hmlet.txt","r").read()
    3. txt = txt.lower()
    4. for ch in '!@#$%^&*()_/*-~':
    5. txt = txt.replace(ch," ")
    6. return txt
    7. hamlet = getText()
    8. words = hamlet.split()
    9. counts = {}
    10. for word in words:
    11. counts[word] = counts.get(word,0) + 1
    12. items = list(counts.items())
    13. items.sort(key= lambda x:x[1],reverse=True)
    14. for i in range(10):
    15. word, count = items[i]
    16. print("{0:<10}{1:>5}".format(word,count))

    现在,我们已经得到了分割后的单词列表words,接下来我们需要统计每个单词出现的次数。我们可以使用Python的字典数据结构来实现词频统计。

    1. word_counts = {}
    2. for word in words:
    3. if word in word_counts:
    4. word_counts[word] += 1
    5. else:
    6. word_counts[word] = 1

    这段代码中,我们首先创建一个空字典word_counts,然后遍历words列表中的每个单词。对于每个单词,如果它已经在word_counts字典中存在,则将对应的计数值加1;否则,在字典中新增一个键值对,键为单词,值为1。

    在统计完词频后,我们需要按照词频降序排序,以便后续输出结果。我们可以使用Python的内置函数sorted()来实现排序。

    sorted_word_counts = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)
    

    我们使用word_counts.items()方法获取word_counts字典中的所有键值对,并使用key=lambda x: x[1]指定按照键值对中的值进行排序,reverse=True表示降序排列。排序结果将保存在sorted_word_counts列表中。

    最后,我们将词频统计结果输出到控制台或文件中。

    1. for word, count in sorted_word_counts:
    2. print(f'{word}: {count}')

    这段代码中,我们使用for循环遍历sorted_word_counts列表中的每个元素(每个元素是一个键值对),并使用print()函数输出单词和对应的词频。

    (2)多篇文章词频统计

    需要使用os.listdir方法读取文件夹下的文件列表,然后对文件逐一进行处理。

    1. import os
    2. folderPath = r'Data/news' #文件夹路径
    3. tmpFile = os.listdir(folderPath)
    4. allNews = []
    5. for file in tmpFile: #读取文件
    6. newsfile = folderPath + '//' + file #拼接完整的文件路径 \\ 转义字符
    7. allNews += readFile(newsfile) #把所有的字符串列表拼接到allText中
    8. print(couWord(allNews,word_list,5))

    输出

    [(465, ‘china’), (323, ‘chinese’), (227, ‘xi’), (196, “china’s”), (134, ‘global’)]

    (3)中文文章的处理

    对于中文文章的词频统计,首先要使用jieba等分词器对文章进行分词,并且加载中文的停止词列表,再进行词频统计。

    3.三国演义人物出场频数

    利用jieba库,进行中文分词,将其存入列表words中,遍历,将词组和词频作为键值对存入列表counts中,利用列表的有序性,进行排序,然后输出

    https://python123.io/resources/pye/threekingdoms.txt

    以上为三国演义中文版文本获取链接,下载后保存到工程路径下

    1. import jieba
    2. txt = open("threekingdoms.txt","r",encoding="utf-8").read()
    3. counts = {}
    4. words = jieba.lcut(txt)
    5. for word in words:
    6. if len(word) == 1:
    7. continue
    8. else:
    9. counts[word] = counts.get(word,0) + 1
    10. items = list(counts.items())
    11. items.sort(key = lambda x:x[1] , reverse=True)
    12. for i in range(15):
    13. word , count = items[i]
    14. print("{0:<10}{1:>5}".format(word,count))

    该方法比英文哈姆雷特词频简单,不用去处理字符类噪声数据,这也得益于jieba库的简易操作。

    但随之带来的是词频的模糊,因为jieba库的特性,导致不是人名的词组也被统计了进来。

    如结果中的“二人”、”孔明曰“,这些都是冗余和词组问题的错误。

    所以我们应该还需要进行进一步的处理,让词频统计人物的名字次数

    经过前几步的操作,我们输出了出现频率最高的15给词组,可我们如果想要人物的出场频率呢? 这就需要对原文件进行过滤,把我们不需要的输出删除。

    因为之前的输出可以简单的获取到出现频率高但不是人名的词组,所以我们这里把它们储存到一个集合中,遍历并删除原文件中存在的这些词组。

    excludes = {"将军","却说","二人","不可","荆州","不能","如此","商议","如何","主公","军士","左右","军马"}
    1. for i in excludes:
    2. del counts[i]

    冗余处理:把出现频率高的相同人物别名进行统一

    1. elif word == "诸葛亮" or word == "孔明曰":
    2. rword = "孔明"
    3. elif word == "关公" or word == "云长":
    4. rword = "关羽"
    5. elif word == "玄德" or word == "玄德曰":
    6. rword = "刘备"
    7. elif word == "孟德" or word == "丞相":
    8. rword = "曹操"

     反复的经过这些处理,我们可以得到我们想要的输出

    1. import jieba
    2. txt = open("threekingdoms.txt","r",encoding="utf-8").read()
    3. counts = {}
    4. excludes = {"将军","却说","二人","不可","荆州","不能","如此","商议","如何","主公","军士","左右","军马"}
    5. words = jieba.lcut(txt)
    6. for word in words:
    7. if len(word) == 1:
    8. continue
    9. elif word == "诸葛亮" or word == "孔明曰":
    10. rword = "孔明"
    11. elif word == "关公" or word == "云长":
    12. rword = "关羽"
    13. elif word == "玄德" or word == "玄德曰":
    14. rword = "刘备"
    15. elif word == "孟德" or word == "丞相":
    16. rword = "曹操"
    17. else:
    18. rword = word
    19. counts[rword] = counts.get(rword,0) + 1
    20. for i in excludes:
    21. del counts[i]
    22. items = list(counts.items())
    23. items.sort(key = lambda x:x[1] , reverse=True)
    24. for i in range(7):
    25. word,count = items[i]
    26. print("{0:<10}{1:>5}".format(word,count))

     

    方法一:运用集合去重方法

    1

    2

    3

    4

    5

    6

    7

    8

    9

    def word_count1(words,n):

       word_list = []

       for word in set(words):

           num = words.counts(word)

           word_list.append([word,num])

           word_list.sort(key=lambda x:x[1], reverse=True)

       for i in range(n):

           word, count = word_list[i]

           print('{0:<15}{1:>5}'.format(word, count))

    说明:运用集合对文本字符串列表去重,这样统计词汇不会重复,运用列表的counts方法统计频数,将每个词汇和其出现的次数打包成一个列表加入到word_list中,运用列表的sort方法排序,大功告成。

    方法二:运用字典统计

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    def word_count2(words,n):

        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(n):

            word, count = items[i]

            print("{0:<15}{1:>5}".format(word, count))

    方法三:使用计数器

    1

    2

    3

    4

    5

    6

    7

    def word_count3(words,n):

        from collections import Counter

        counts = Counter(words)

        for ch in "":  # 删除一些不需要统计的元素

            del counts[ch]

        for word, count in counts.most_common(n):  # 已经按数量大小排好了

            print("{0:<15}{1:>5}".format(word, count))

  • 相关阅读:
    「链判断运算符」“?.”和「Null 判断运算符」“??”构建失败
    如何计算 R 中的基尼系数(附示例)
    探索在云原生环境中构建的大数据驱动的智能应用程序的成功案例,并分析它们的关键要素。
    Linux共享内存与子进程继承
    CubeMX安装和使用指南
    Mybatis方式完成CRUD操作
    ZMTP协议
    第12章 最佳的UI体验——Material Design实战
    【LeetCode】No.75. Sort Colors -- Java Version
    GetPrivateProfileSection使用
  • 原文地址:https://blog.csdn.net/greatau/article/details/134044945