python分词考研英语真题词频(附结果)——读取word、nltk、有道智云API

打算用python分析一次啊考研真题单词的词频,并加上翻译等内容,方便背诵

读取word文件

手头有近20年的考研英语一二真题word文件几十个,需要对每个文件的内容进行读取,并提取属于文章和题目的部分,即去掉介绍部分

python分词考研英语真题词频(附结果)——读取word、nltk、有道智云API_第1张图片

使用docx包来读取word,因为只支持docx后缀,所以原有文件另存为docx形式
导入库,并设立要去掉的标点符号以及停用词,其中停用词通过nltk库from nltk.corpus import stopwords 导入

from docx import Document
import nltk
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
import re
from nltk.stem import PorterStemmer
from nltk.stem.lancaster import LancasterStemmer
from nltk.stem.snowball import SnowballStemmer
from nltk.stem import WordNetLemmatizer


interpunctuations = [',', '.', ':', ';', '?', '(', ')', '[', ']', '&', '!', '*', '@', '#', '$', '%', '_', '-', '—', '"', '“', '”', "'"]
stops = set(stopwords.words("english"))

通过docx的Document方法可以读取word文件,将要读取的文件组成一个列表

docxs1 = [Document(str(year)+'-1.docx') for year in range(1998, 2022)]

分词

下面输入文件名列表,输出分好词的列表

def get_words(docxs):    # 输入文件名列表,输出单词列表(去标点数字符号,题目要求标题)
    words = []   # 储存单词
    for doc in docxs:    # 遍历每一个文件
        for para in doc.paragraphs:     # 遍历文件中的每一个段落
            if len(para.runs)>=1 and len(para.text)>=1:   # 确实是有效段落
                if para.runs[0].font.bold or para.runs[0].font.italic:  # 如果是粗体或者斜体,不处理
                    continue
                # s = re.sub(r'[.*?]', ' ', para.text)
                s = re.sub(r'[[A-Z]+]', ' ', para.text)   # 去掉特殊符号
                s = re.sub(r'[0-9]+', ' ', s)
                s = re.sub(r'②|③|①|④|⑤|⑥|⑦|⑧|⑨|⑩|⑪|⑫|⑬|⑭|⑮|⑯|⑰|_|—|-|\.', ' ', s)
                s = re.sub(r'\[0-9a-z]', ' ', s)
                # print(s)
                s_words = word_tokenize(s)  # 分词
                
                # print(s_words)
                cutwords = [word for word in s_words if word not in interpunctuations] 
                cutwords = [word.lower() for word in cutwords if word not in stops]   # 去除停用词与标点
                if cutwords:
                    if cutwords[0] == 'read' or cutwords[0] == 'translate':   # 有的翻译和阅读题目介绍没有粗体和斜体
                        continue
                words+=cutwords
    return words
    

docx 中的 runs 一个run对象是相同样式文本的延续(只要文本的格式没有改变,那么就是一个run,一旦改变了就是列外一个run了) 所以我们使用para.runs[0].font.bold or para.runs[0].font.italic来判断这一段的开头是否为粗体或者斜体
因为在文件中,题目介绍是粗体或斜体,这部分不参与统计:

python分词考研英语真题词频(附结果)——读取word、nltk、有道智云API_第2张图片

使用re库 正则表达式re.sub来替换特殊符号等为空格,后续分词可直接分开 re.sub使用参考https://blog.csdn.net/jackandsnow/article/details/103885422
其中[[A-Z]+]为中括号里面带字母的,[0-9]+为连续或非连续数字,②|③|①|④|⑤|⑥|⑦|⑧|⑨|⑩|⑪|⑫|⑬|⑭|⑮|⑯|⑰|_|—|-|.为特殊符号,因为.表示所有除换行符以外的符号,所以在前面加\转义,表示为.本身

python分词考研英语真题词频(附结果)——读取word、nltk、有道智云API_第3张图片
python分词考研英语真题词频(附结果)——读取word、nltk、有道智云API_第4张图片

分词 使用nltk中的word_tokenize进行分词,去除停用词与标点符号,最后将所有文件和段落分词列表叠加,输出words

NLTK词干提取(词形还原)

为了提高词性还原的准确度,采用nltk的WordNetLemmatizer方法,WordNetLemmatizer可通过单词,词性(可选)两个参数提取词干,为了提高准确率,首先提取每一个单词的词性

>>> from nltk.stem import WordNetLemmatizer
>>> import nltk
>>> lem = WordNetLemmatizer()
>>> nltk.pos_tag(['better'])
[('better', 'RBR')]
>>> lem.lemmatize('better', 'RBR')
Traceback (most recent call last):
  File "", line 1, in <module>
  File "D:\anaconda\lib\site-packages\nltk\stem\wordnet.py", line 38, in lemmatize
    lemmas = wordnet._morphy(word, pos)
  File "D:\anaconda\lib\site-packages\nltk\corpus\reader\wordnet.py", line 1906, in _morphy
    exceptions = self._exception_map[pos]
KeyError: 'RBR'
>>> lem.lemmatize('better', 'a')
'good'
>>> lem.lemmatize('better', wordnet.ADV)
'well'
>>> lem.lemmatize('better', wordnet.ADJ)
'good'

如上可看出,pos_tag可获得单词的词性,但词性直接用作lemmatize的参数会发生错误,所以需要转换一下(应该是NLTK的小缺憾),可以用的参数为wordnet里面的词性
转换函数:

from nltk.corpus import wordnet
def get_wordnet_pos(tag):       # 词性转化翻译
    if tag.startswith('J'):
        return wordnet.ADJ
    elif tag.startswith('V'):
        return wordnet.VERB
    elif tag.startswith('N'):
        return wordnet.NOUN
    elif tag.startswith('R'):
        return wordnet.ADV
    else:
        return ''

获得词干:输入单词列表,输出词干列表

def get_stems(words):   # 获得词干
    lem = WordNetLemmatizer()    # 词形还原
    words_tag = nltk.pos_tag(words)
    words_final = []
    for couple in words_tag:
        if couple[0][0]<'a' or couple[0][0]>'z' or len(couple[0])<=1:   # 去除非单词及空格
            continue
        if get_wordnet_pos(couple[1]):
            words_final.append(lem.lemmatize(couple[0], get_wordnet_pos(couple[1])))
        else:
            words_final.append(lem.lemmatize(couple[0]))
    return(words_final)

统计个数

import collections
coun = dict(collections.Counter(words_final).most_common())

使用collections库的counter,返回每个单词及其个数,most_common(n)为返回由大到小前n个,默认为从大到小返回全部

python分词考研英语真题词频(附结果)——读取word、nltk、有道智云API_第5张图片

翻译

这里使用有道智云的文本翻译API,参照文档中的python3写法
文本翻译API文档

使用参考
https://zhuanlan.zhihu.com/p/59527880

import uuid
import requests
import hashlib
import time
import json

# APPID 与 秘钥
appid = '****'
secretKey = '********'
myurl = 'https://openapi.youdao.com/api'

def encrypt(signStr):
    hash_algorithm = hashlib.sha256()
    hash_algorithm.update(signStr.encode('utf-8'))
    return hash_algorithm.hexdigest()

def translate(q):

    # 将key设置为字典,填写参照文档
    data = {}
    data['from'] = 'en'
    data['to'] = 'zh-CHS'
    data['signType'] = 'v3'
    curtime = str(int(time.time()))
    data['curtime'] = curtime
    salt = str(uuid.uuid1())
    signStr = appid + q + salt + curtime + secretKey
    sign = encrypt(signStr)
    sign = encrypt(signStr)
    data['appKey'] = appid
    data['q'] = q
    data['salt'] = salt
    data['sign'] = sign
    headers = {'Content-Type': 'application/x-www-form-urlencoded'}

    # 使用requests的post获取
    response = requests.post(myurl, data=data, headers=headers)
    # print(response.content)

    # 对response的内容解码
    result_all = response.content.decode("utf-8")
    # 转换为json形式
    result = json.loads(result_all)
    if 'basic' in result:
        return result['basic']['explains']
    else:
        return '释义错误'

最后的result为一个字典,里面有包括源词、语言、翻译等
其中字典的解释在basic中的explains中,故进行提取,若没有,说明单词出现错误

def translate_alls(coun):
    ans = {}
    for k,v in coun.items():
        trans = translate(k)
        ans[k] = [v, trans]
    return ans

translate_alls函数:输入统计的单词,对于每一个单词,进行翻译,并把单词、翻译、词频放入同一个字典中

综上

将上面的函数进行操作

words_1 = get_words(docxs1)  # 由文件获得分词列表
words_final_1 = get_stems(words_1)  # 获得词干列表
coun_1 = dict(collections.Counter(words_final_1).most_common()) # 进行统计
ans_1 = translate_alls(coun_1)  # 调用API获得翻译+词频字典

python写入Excel

这里使用openpyxl进行Excel的读写

from openpyxl import Workbook, load_workbook

wb = load_workbook('words_times.xlsx')  # 加载文件
ws_2 = wb.create_sheet('考研英语一1')  # 建立新sheet

for k,v in ans_1.items():  # 对于字典中每一项,写入一行
    ws_2.append([k, v[0], str(v[1])])
wb.save('words_times.xlsx')  # 保存

结果

python分词考研英语真题词频(附结果)——读取word、nltk、有道智云API_第6张图片

单词结果自取:

链接:https://pan.baidu.com/s/1Zdr8yDZ607ZuGMxjJQg28A
提取码:s985

结果分为英一、英二、英一+英二

你可能感兴趣的:(Python杂七杂八,考研,python,自然语言处理,nltk,api,数据分析)