当前位置:   article > 正文

Python处理中文文本_python自然语言处理基础实验2中文关键词提取

python自然语言处理基础实验2中文关键词提取

Python处理中文文本

author:Ernest

使用Python处理文本是件十分有趣的任务,通过某些操作,你可以自由地获取到你所需要的内容,下面就来看看怎么做吧。

要求

1.选择一部长度合适的小说,中文、英文或其他语种皆可,长度不低于5万字。
2.首先对文本进行词(字)频统计,中文可以进行分词统计词频,或不分词统计字频,英文要求统计词频并考虑词语的大小写等价性。
3.按照词频顺序列出所有的词及其出现次数;
4.绘制排序-数量曲线,验证Zipf-Law(可以用第三方软件绘图)。
5.利用正则表达式查找文件中的某种特定模式,对这种模式进行提取分析。要求提取出的内容有一定的复杂性(多种匹配结果),提取的数量不低于20个。

开始处理

1.读取文本

这里我们选择《自律胜于纪律》一书,资源上百度网盘
(链接:https://pan.baidu.com/s/15E4HiJZwtnOdv1Ql4tFlmQ 提取码:72jd )
Python打开文本的写法有两种,一种是直接使用open()方法,返回文件对象,使用完毕后要使用close()方法关闭文件对象;另一种是使用with open() as f写法,你只管打开文件,并在需要时使用它,Python自会在合适的时候自动将其关闭,详看下方代码解释。

path = r'自律胜于纪律.txt'  # 要打开的文件,这里使用相对路径(关于Windows下使用相对路径和绝对路径的方法见下文)

'''写法一'''
f = open(path, 'r')	# f即为open()方法返回的文件对象,后续对文件的一切操作都是基于这个对象
str = f.read()  	# 读取文本
print(str)          # 对读取到的文本输出看一下效果
f.close() 			# 关闭文件对象

'''写法二'''
with open(path, 'r', encoding='utf8') as f:	# 此处已经打开文件并将 f 作为文件对象
	str = f.read()	# 读取文本
# 到这里时 f 文件对象已经不再使用,会自动关闭
print(str)			# 对读取到的文本输出看一下效果,这里只能操作 str ,不能再操作 f 对象
s = f.read()		# 报错!!!f 对象的作用域只能在上面的 with 块内
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

一般对文件进行各种操作都使用with open() as f写法,关键字with在不再需要访问文件后将其关闭,你当然可以使用open()close()来打开和关闭文件,但这样做时一方面如果程序存在bug导致close()没有执行,文件将不会关闭,这看似微不足道,但未妥善地关闭文件可能会导致数据丢失或受损;另一方面如果在程序中过早地使用close(),你会发现需要使用文件时它已经关闭,这会导致更多的错误,并非在任何情况下你都能轻松确定关闭文件的恰当时机,但通过with关键字来操作,你完全可以将这个问题交给Python,你只管打开并使用它。

【关于绝对路径与相对路径】

在这里插入图片描述

假使文件位置如上图所示
使用绝对路径打开txt文件:

text = open("D:\\study\\Python\\TXT\\test.txt").read()
print(text)
  • 1
  • 2

使用相对路径打开txt文件:

text = open("..\\TXT\\test.txt").read()
print(text)
  • 1
  • 2

其中,使用双反斜杠(\)是因为Python中将反斜杠()作为转义字符,这里使用单反斜杠将会报错,而Linux与Mac OS则不必担心;相对路径中的两个点(…)表示返回此文件的上一级目录,一个点(.)表示此文件的所在目录。

2.分词并进行词频统计

中文分词使用jieba库进行,词频统计则直接对分词结果进行遍历统计即可。
jieba分词库的使用这里不作介绍,百度即可。

import jieba

# 使用jieba分词
all_words = jieba.lcut(txt)
counts = {}
# 词频统计
for word in all_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)
sort_li = sorted(counts.values(), reverse=True)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

得到词频统计的结果之后将其写入csv文件中,并且绘制排序-数量曲线,这里使用matplotlib库进行二维图像绘制。

import matplotlib.pyplot as plt

# 将排序结果写入到csv文件中
pd.DataFrame(items).to_csv('自律胜于纪律.csv', encoding='utf-8_sig')
X = [i for i in range(len(sort_li))]
plt.plot(X, sort_li, 'r')
plt.xscale('log')
plt.yscale('log')
plt.xlabel('word number')
plt.ylabel('word frequency')
plt.title('Word Frequency Statistics')
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述
这是输出到csv文件中的效果,共计出现11071个词。

在这里插入图片描述

这是绘制的排序-数量图,可以明显验证齐普夫定律(Zipf’s law),通过查看csv文件,词频在100以上的词仅有不到50个,占总词数的0.45%。

3.正则表达式匹配

使用正则表达式对小说中的内容进行提取,Python正则表达式的用法这里不作介绍,百度即可。
1.匹配小说中所有章节名

pat_chapter = '第\\d+章.{8}'	# 正则表达式
chapter = re.findall(pat_chapter, txt)	# 使用findall()方法进行全文匹配
if chapter:	# 如果成功匹配到
	for item in chapter:
    	print(unicodedata.normalize('NFKC', item)) # 使用unicodedata将空格字符正常显示
else:
	print("匹配失败")
'''
输出如下:
第1章 自律是一种信仰
第2章 自律是一种自省
第3章 自律是一种自警
第4章 自律是一种素质
第5章 自律是一种自爱
第6章 自律是一种觉悟
第7章 管好自己的目标
第8章 管好自己的言行
第9章 管好自己的时间
第10章 管好自己的习惯
第11章 管好自己的情绪
第12章 管好自己的心态
第1章 自律是一种信仰
第2章 自律是一种自省
第3章 自律是一种自警
第4章 自律是一种素质
第5章 自律是一种自爱
第6章 自律是一种觉悟
第7章 管好自己的目标
第8章 管好自己的言行
第9章 管好自己的时间
第10章 管好自己的习惯
第11章 管好自己的情绪
第12章 管好自己的心态

进程已结束,退出代码0
'''
#已匹配到文中全部章节名,符合要求
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

2.多个匹配
可以发现这样的匹配是可行的,但是如果想要一次性匹配多种、多个内容,但又想避免写出重复代码,这个时候字典的作用就体现出来了。

'''正则匹配'''
def selectSome(txt):
    # 匹配所有章节名
    pattens = {
        '所有章节名' : '第\\d+章.{8}',
        '人名-罗纳德' : '.{3}罗纳德.{3}',
        '所有出现的书籍' : '《[^》]*》',
        '所有人物说的话' : '.{8}:“[^”]*”',
        '所有引用但不是以冒号引出的第一人称说的话' : '[^:]“[^”]*”',
        '所有顿号的词' : '[,。:?“][^,。:?]*、.*[,|。]{1}'
    }
    for key, value in pattens.items():
        print('=====================    下面是' + key + '  =====================')
        chapter = re.findall(value, txt)
        nums = 1
        if chapter:
            for item in chapter:
                print(str(nums) + '.  ' + unicodedata.normalize('NFKC', item))  # 使用unicodedata将空白字符正常显示
                nums += 1
        else:
            print("匹配失败")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

这样只需要修改字典中的正则键值对即可实现一次性完成所有的匹配了,运行结果太长,这里不作展示,读者可自行运行代码体验。

总结及源码

上述操作涉及Python的基本语法、正则表达式的用法以及jieba、pandas、matplotlib、unicodedata等库的使用,难度系数不大,适宜练手熟悉各种函数的用法,读者可基于此再进行更多的操作练习。
创作不易,切勿侵权照搬。

源码
'''
Python实现文本处理
@author: Ernest
2021-6-3
'''
import jieba
import pandas as pd
import unicodedata
import matplotlib.pyplot as plt
import re

'''词频统计'''
def word_freq(txt):
    # 使用jieba分词
    all_words = jieba.lcut(txt)
    counts = {}
    # 词频统计
    for word in all_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)
    sort_li = sorted(counts.values(), reverse=True)
    # 将排序结果写入到csv文件中
    pd.DataFrame(items).to_csv('自律胜于纪律.csv', encoding='utf-8_sig')
    # 绘制排序-数量曲线
    X = [i for i in range(len(sort_li))]
    plt.plot(X, sort_li, 'r')
    plt.xscale('log')
    plt.yscale('log')
    plt.xlabel('word number')
    plt.ylabel('word frequency')
    plt.title('Word Frequency Statistics')
    plt.show()

'''正则匹配'''
def selectSome(txt):
    # 所有想要匹配的正则表达式
    pattens = {
        '所有章节名' : '第\\d+章.{8}',
        '人名-罗纳德' : '.{3}罗纳德.{3}',
        '所有出现的书籍' : '《[^》]*》',
        '所有人物说的话' : '.{8}:“[^”]*”',
        '所有引用但不是以冒号引出的第一人称说的话' : '[^:]“[^”]*”',
        '所有顿号的词' : '[,。:?“][^,。:?]*、.*[,|。]{1}'
    }
    for key, value in pattens.items():
        print('=====================    下面是' + key + '  =====================')
        chapter = re.findall(value, txt)
        nums = 1
        if chapter:
            for item in chapter:
                print(str(nums) + '.  ' + unicodedata.normalize('NFKC', item))  # 使用unicodedata将空白字符正常显示
                nums += 1
        else:
            print("匹配失败")

def main():
    # 读取文本
    with open(r'自律胜于纪律.txt', 'r', encoding='utf8') as TJ:
        txt = TJ.read()
    selectSome(txt)
    word_freq(txt)

if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/281808
推荐阅读
相关标签
  

闽ICP备14008679号