Python:使用给定的语料库去构建二元语法模型

问题:写一个Python程序,使用给定的语料库(metadata.txt的第三列文本),构建二元语法模型,用MLE(最大似然估计)去估计bigram的概率,可以不使用数据平滑技术。

需要使用控制台输入法演示该语言模型:当输入一个单词后,程序自动推荐接下来最可能输入的5个单词,如果用户根据推荐或自主输入下一个单词,程序以同样的方式推荐接下来最可能输入的5个单词,以此使用户循环输入。


原始数据metadata.txt见此链接


程序1,extract_data.py:将原始数据metadata.txt的第三列摘出来放到一个新文本文件newdata.txt中。本程序无输出结果,但是会生成一个文件newdata.txt。

# 本程序功能:将原始数据的第三列摘出来放到一个新文本文件中

import os

os.chdir(r'D:\\') # 假设这是原始语料metadata.txt所在的根目录

with open('metadata.txt', 'r', encoding='utf8') as file_object:
    a = file_object.readlines() # 将文本的每一行作为一个字符串存在列表a里
    s = ''
    for i in a:
        i = i.split('|') # 每一行按'|'分开
        i = i[-1] # 取最后一项,也就是文本内容的第三列
        i = i.replace('\n', ' ') # 把换行替换为空格
        s += i
with open('newdata.txt', 'w', encoding='utf8') as file_object: # 新内容放在newdata.txt中
    file_object.write(s)

程序2,generate_base.py:根据语料库newdata.txt生成一个库文件words_base.json。本程序在运行结束后会输出成功提示,以及程序运行时间(一般需要10分钟左右),还会输出出现次数最多的五个词,另外生成一个文件words_base.json。

# 本程序功能:根据语料库newdata.txt生成一个库文件words_base.json
import os, re, json, time

start = time.time() # 程序开始运行
os.chdir(r'D:\\')

all_words = [] # 用来存放所有单词

with open('newdata.txt', 'r', encoding='utf8') as file_object:
    contents = file_object.read()  # 将文本中的全部字符作为一个字符串
    all_words = re.findall(r'\b[a-zA-Z]+\b', contents)  # 所有的单词,每个单词可能出现不止一次,有重复的单词
    all = list(sorted(set(all_words)))  # 去除多余的单词
    l = len(all_words)  # 语料库中所有单词的个数,包括重复的单词

class Words: # 构建一个词类
    def __init__(self, word):
        self.word = word
        self.word_times = 0  # 本单词在语料库中出现的次数,开始假设为0
        self.word_lists = []  # 所有的本单词后面紧跟着的第一个单词
        self.word_dicts = [] # 所有的本单词后面紧跟着的第一个单词中,每个单词对应一个由自身和概率两个字段构成的一个字典,word_dicts为一个由字典组成的列表

words_base = []  # 库

for word in all:
    w = Words(word)
    tmps = []
    for i in range(l):
        if all_words[i] == w.word:
            w.word_times += 1
            if i != l - 1:  # 将与当前单词相同的单词的后一个单词存入列表;如果与当前单词相同的是所有单词的最后一个的话,则后面没有单词了,需要跳过
                tmps.append(all_words[i + 1])
    w.word_lists = list(sorted(set(tmps))) # 去除重复项
    for t in w.word_lists:
        times = 0
        for tmp in tmps:
            if t == tmp:
                times += 1
        w.word_dicts.append({'word':t, 'prob': '%.3f' % (times/w.word_times)}) # 两个字段单词及对应的概率
    w.word_dicts = sorted(w.word_dicts, key=lambda x: x['prob'], reverse=True) # 根据概率从大到小,将【字典列表】排序
    words_base.append([w.word, w.word_times, w.word_dicts])

words_base = sorted(words_base, key=lambda x: x[1], reverse=True) # 按每个单词在语料库出现的次数由大到小排列

with open('words_base.json', 'w') as file_object: # 把内容保存到json文件中,方便后续使用,否则每次测试时都需要重新运行程序
    json.dump(words_base, file_object)

end = time.time() # 程序结束运行

print('Successful!')

print('This program has run for about ' + str(int(end-start)) + 's')

ss = ''

for tt in words_base[:5]:
    ss += tt[0] + ' '

print('出现次数最多的五个词是:' + ss)

输出为:

Successful!
This program has run for about 673s
出现次数最多的五个词是:the of and to in

程序3,test.py:本程序主要用来测试:根据提示操作就行,程序会根据用户输入的内容调整输出【最可能输入的5个单词】,并输出目前用户输入的历史,之后不断要求用户输入。若用户输入q,程序停止。

如果输入的词在语料库中,则输出前五个概率最大的单词;如果不够五个,就用总共出现次数最多的几个词去补,缺几个补几个。如果输入的词不在语料库中,则直接输出出现次数最多的五个词。

import os, json

os.chdir(r'D:\\')

with open('words_base.json', 'r') as file_object:
    words_base = json.load(file_object) # 将库文件内容加载到变量中

# 下面是出现次数最多的五个词
s = ['the', 'of', 'and', 'to', 'in']
input_words = '' # 输入的单词历史

while True:
    ss = ''  # 用于输出待选词
    input_word = input('请输入一个单词,退出请按"q"\n:')
    if input_word == 'q':
        break

    flag = 0 # 检验输入的单词是否存在于语料库中,开始假设未出现在语料库

    for w in words_base:
        if w[0] == input_word:
            flag = 1 # 出现在了语料库就赋值为1
            times = 0
            for i in range(len(w[2][:5])): # 只输出前五个
                ss += str(i+1) + ' ' + w[2][i]['word'] + ' '
                times += 1
            if times < 5: # 不够五个就按出现次数最大的单词去补
                for i in range(5-times):
                    ss += str(times+i+1) + ' ' + s[i] + ' '

    if flag == 0: # 如果输入的单词不存在于语料库中,则输出出现次数最多的五个词
        for i in range(5):
            ss += str(i+1) + ' ' + s[i] + ' '
    print(ss)
    input_words += input_word + ' '
    print('您目前已经输入的句子为:', input_words, '\n')

输出:这只是一个我自己输入的序列,你可以自由发挥。

请输入一个单词,退出请按"q"
:You
1 have 2 and 3 can 4 who 5 will 
您目前已经输入的句子为: You  

请输入一个单词,退出请按"q"
:will
1 be 2 not 3 also 4 have 5 come 
您目前已经输入的句子为: You will  

请输入一个单词,退出请按"q"not
1 be 2 only 3 to 4 have 5 the 
您目前已经输入的句子为: You will not  

请输入一个单词,退出请按"q"
:have
1 been 2 a 3 to 4 seen 5 the 
您目前已经输入的句子为: You will not have  

请输入一个单词,退出请按"q"
:a
1 man 2 few 3 great 4 good 5 number 
您目前已经输入的句子为: You will not have a  

请输入一个单词,退出请按"q"
:good
1 deal 2 a 3 for 4 intentions 5 shot 
您目前已经输入的句子为: You will not have a good  

请输入一个单词,退出请按"q"
:deal
1 of 2 with 3 and 4 more 5 He 
您目前已经输入的句子为: You will not have a good deal  

请输入一个单词,退出请按"q"
:q

评价

我没有使用数据平滑技术,这三个程序中有好几个变量的数据类型都是复合类型,较为复杂,且在程序2中定义的Words类的用处也只是为了方便管理变量,并没有实现类方法,后期改进时,可以将程序中的几个程序片段放在类方法中,这样主程序就更易懂了。


END

  • 5
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值