自动完形填空系统构建

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Kangyucheng/article/details/80771847

自动完形填空系统构建要求

问题描述

在语义连贯的句子中去掉一个词语,形成空格,要求在给出的对应备选答案中,系统自动选出一个最佳的答案,使语句恢复完整。

相关语料

1Training data:未标注训练语料,供同学选择使用。同学也可根据需要自行选择其他语料,但需要在在实验报告中注明所使用训练语料的规模、来源及性质。

2Development set:
提供一份含有
240 句话的语料及答案,供同学自行测试结果,根据结果调整优化自己的算法。

3Test set:
提供一份含有
800 句话的测试语料,每句话有一个空格和 5 个备选答案。该语料不提供答案,同学提交测试结果,由助教统一评测。

评测方法

准确率=正确填空句子的个数/全部句子的个数

题目要求

要求同学根据自己设计训练得到的系统,对测试语料进行预测,对每句话提供一个系统认为正确的选项。

本作业无统一标准方法,同学可自行设计模型,鼓励同学积极创新。

提示:模型的构建可以简单也可以复杂。例如,可以基于 n 元模型建立一个朴素的系统;也可以引入词性、句法树等;也可以使用神经网络等其他方法;可以使用自行搜集到的词典或者规则作为辅助。当然不限于这些方法,鼓励创新。

作业要求

1、可分组进行,但每个小组的规模不能超过 2 (2)

2、实现相关程序,可用 c/c++Python 以及 java 语言完成。可参考网上源代码,但必须重新实现,要求程序代码完整,有必要的说明文档和 Makefile 等文件;

3、提供测试语料的预测结果,输出文件以“题目号+选项+英文单词”形式输出,中间用空格或制表符间隔,每个答案占一行。例如:

1 choice1 answer1

...... ......
...... ......
800 choice 800 answer800

4、撰写实验报告以及 PPT。实验报告以小论文的形式,要有必要的参考文献等信息,将使用的方法讲解清楚;PPT 用于在课堂上报告实验成果;

5、将预测答案、实验报告、PPT 及源程序提交到助教用以评分。

自动完形填空系统构建实验报告

第一章  基于n元模型构建的朴素系统

1.1         问题描述

在语义连贯的句子中去掉一个词语,形成空格,每个空格有5个备选答案,要求在给出的对应备选答案中,系统自动选出一个最佳的答案,使语句恢复完整。

1.2         系统分析

n元模型中,一个词的出现只与它的前n-1个词有关。填空题的句子只有一个空格,设空格在句子中的位置为i,则i-2,i-1,i+1位置上的三个词对于空格处应填词语十分重要。因此,本系统采用2元模型与3元模型相结合的办法。

1.3         系统设计与实现

系统可分为训练数据、保存训练数据、选择答案、保存结果等部分。其大致流程如图1.1所示。

图1.1 系统流程图

1.3.1读取数据集

将词频、二元模型、三元模型的统计结果存储到字典当中,字典的key代表词和词组,字典的value代表在语料中出现的次数,将字典分别写入三个文件当中。统计结果如图1.2所示。

图1.2  统计结果

1.3.2  读取数据集

在训练好数据集之后,将上一步写好的文件读出来,存到字典当中,字典的key代表词和词组,字典的value代表在语料中出现的次数。

1.3.3  选择答案

每一道题分成题目和选项两部分,针对每个选项计算四个参数,计算过程如图1.3所示。根据四个概率相关的参数,选择最佳答案。选择过程如图1.4所示。


图1.3  计算过程

图1.4  参数选择过程

1.4         实验过程与结果

1.4.1  实验过程

首先配置python2.7,安装pip,按照官网提示安装nltk,在pycharm中创建工程,并将数据集和测试集放在工程的目录下,创建mynlp.py文件开始编码,结果如图1.5所示

图1.5  编码结果

1.4.2  实验结果

运行mynlp.py文件,分别得到相关的文件结果。创建test.py,将计算结果与正确答案进行比较。比较结果如图1.6所示,正确率可达到30%。

图1.6  测试结果

 

源码

# encoding=utf-8
from nltk.util import ngrams
from nltk import word_tokenize
from nltk import sent_tokenize
import os


class mynlp:

    training_data_path = 'Training_Data'  # 该文件夹下存储着所有的训练数据
    test_data_path = 'Test_Data/development_set.txt'   # 该文件存储着用于开发的测试文档
    result_file_path = 'result.txt'    # 发送给助教的结果
    #test_data_path = 'Test_Data/test_set.txt'
    training_gram1_res = {}  # 存储一元模型的结果(词频)
    training_gram2_res = {}  # 存储二元模型的结果
    training_gram3_res = {}  # 存储三元模型的结果
    result_list = []         # 存储计算结果

    def __init__(self):
        self.start()

    def start(self):
        # 第一步,读取数据集,将词频、二元模型、三元模型存储到字典当中,将元组写入一个文件当中,训练一次后可注释掉
        # self.train_data()
        # 第二步,将写好的文件读出来,存到字典当中,(an,apple) :  2
        self.read_from_training()
        # 第三步,针对每一道题,将每个答案放到句子中,计算这个词和前一个词与后一个词分别的2元模型,选取概率最大的那个
        self.select_result()
        # 第四步,将结果写入文件,发给助教
        self.write_result()

    def train_data(self):

        datafiles = os.listdir(self.training_data_path)
        for i in datafiles:
            filename = self.training_data_path+'/'+i
            f = open(filename)
            data = self.clear_string(str(f.readlines()))
            data_sent = sent_tokenize(data)
            for j in data_sent:
                data_words = word_tokenize(j)

                # 训练一元组,求频率
                for t in data_words:
                    # t = self.clear_string(t)
                    if t in self.training_gram1_res:
                        self.training_gram1_res[t] += 1
                    else:
                        self.training_gram1_res[t] = 1

                # 训练二元组
                training_gen = ngrams(data_words, 2)
                for k in training_gen:
                    # k = self.clear_string(k)
                    if k in self.training_gram2_res:
                        self.training_gram2_res[k] += 1
                    else:
                        self.training_gram2_res[k] = 1

                # 训练三元组
                training_gen = ngrams(data_words, 3)
                for b in training_gen:
                    # b = self.clear_string(b)
                    if b in self.training_gram3_res:
                        self.training_gram3_res[b] += 1
                    else:
                        self.training_gram3_res[b] = 1
            f.close()

        result_file1 = open('result_1.txt', 'w')
        for i in self.training_gram1_res:
            result_file1.writelines(str(i)+'  '+str(self.training_gram1_res[i])+'\n')
        result_file1.close()

        result_file2 = open('result_2.txt', 'w')
        for i in self.training_gram2_res:
            result_file2.writelines(str(i)+'  '+str(self.training_gram2_res[i])+'\n')
        result_file2.close()

        result_file3 = open('result_3.txt', 'w')
        for i in self.training_gram3_res:
            result_file3.writelines(str(i)+'  '+str(self.training_gram3_res[i])+'\n')
        result_file3.close()

    def clear_string(self, s):
        if len(s) > 1:
            return s.replace('\\r', '').replace('\\n', '').replace('\\', '').replace("'", "").replace("`", "")
        else:
            return s

    def read_from_training(self):

        read_file1 = open('result_1.txt', 'r')
        for i in read_file1:
            read_gram_key = i.split("  ")[0]
            read_gram_num = int(i.split("  ")[1].replace('\n', ''))
            self.training_gram1_res[read_gram_key] = read_gram_num
        read_file1.close()

        read_file2 = open('result_2.txt', 'r')
        for i in read_file2:
            read_gram_key = i.split("  ")[0]
            read_gram_num = int(i.split("  ")[1].replace('\n', ''))
            self.training_gram2_res[read_gram_key] = read_gram_num
        read_file2.close()

        read_file3 = open('result_3.txt', 'r')
        for i in read_file3:
            read_gram_key = i.split("  ")[0]
            read_gram_num = int(i.split("  ")[1].replace('\n', ''))
            self.training_gram3_res[read_gram_key] = read_gram_num
        read_file3.close()

    def select_result(self):
        test_file = open(self.test_data_path, 'r').readlines()
        index = 0
        while index < len(test_file):
            question = test_file[index]
            choices = {}
            for l in range(5):
                k = test_file[index+l+1].split()[0]
                v = test_file[index+l+1].split()[1]
                choices[k] = v
            result = self.get_best_choice(question, choices)
            # print result
            self.result_list.append(result)
            index += 8

    def get_best_choice(self,question,choices):
        result = []
        q = question.split()
        question_num = q[0]
        space = q.index('_____')
        pre_pre = q[space-2]
        pre = q[space-1]
        nex = q[space+1]

        for c in choices:
            p31 = self.get_p3(pre_pre,pre,choices[c])
            p32 = self.get_p3(pre,choices[c],nex)
            p21 = self.get_p2(pre,choices[c])
            p22 = self.get_p2(choices[c],nex)
            l = [c,p31,p32,p21,p22]
            result.append(l)

        find = False
        # print question_num
        max_choice = ''

        #第一步,选出p32*p31最大的
        max_p32_mul_p31 = float(0)
        for i in range(5):
            if result[i][1] * result[i][2] > max_p32_mul_p31:
                max_p32_mul_p31 = result[i][1] * result[i][2]
                max_choice = result[i][0]
                find = True
                # print 'p32*p31'

        # 第二步,如果第一步没选出来,选出p32最大的
        max_p32 = float(0)
        if not find:
            for i in range(5):
                if result[i][2] > max_p32:
                    max_p32 = result[i][2]
                    max_choice = result[i][0]
                    find = True
                    # print 'p32'
            if max_p32 < 0.0005:
                find = False

        # 第三步,如果第一、二步没选出来,选出p31最大的
        max_p31 = float(0)
        if not find:
            for i in range(5):
                if result[i][1] > max_p31:
                    max_p31 = result[i][1]
                    max_choice = result[i][0]
                    find = True
                    # print 'p31'
            if max_p31 < 0.0005:
                find = False

        # 第四步,如果第一、二、三步没选出来,选出p21*p12最大的
        max_p21_mul_p12 = float(0)
        if not find:
            for i in range(5):
                if result[i][3]*result[i][4] > max_p21_mul_p12:
                    max_p21_mul_p12 = result[i][3]*result[i][4]
                    max_choice = result[i][0]
                    find = True
                    # print 'p2*p1'
        # 第五步,如果第一、二、三、四步没选出来,选出p21最大的
        max_p21 = float(0)
        if not find:
            for i in range(5):
                if result[i][3] > max_p21:
                    max_p21 = result[i][3]
                    max_choice = result[i][0]
                    find = True
                    # print 'p21'
        # 第六步,如果第一、二、三、四、五步没选出来,选出p22最大的
        max_p22 = float(0)
        if not find:
            for i in range(5):
                if result[i][4] > max_p22:
                    max_p22 = result[i][4]
                    max_choice = result[i][0]
                    find = True
                    # print 'p22'
        # 第七步,如果第一、二、三、四、五、六步没选出来,选e
        if not find:
            max_choice = 'e)'
            # print 'e'

        return question_num+' ['+max_choice.replace(')','')+'] '+str(choices[max_choice])

    def get_p3(self, pre, mid, nex):
        c = float(0)
        k3 = "('"+pre+"', '"+mid+"', '"+nex+"')"
        k2 = "('"+pre+"', '"+mid+"')"
        if k3 in self.training_gram3_res:
            c = float(self.training_gram3_res[k3])/float(self.training_gram2_res[k2])
        return c

    def get_p2(self, v1, v2):
        c = float(0)
        k = "('"+v1+"', '"+v2+"')"
        if k in self.training_gram2_res:
            c = float(self.training_gram2_res[k])/float(self.training_gram1_res[v1])
        else:
            if v1 in self.training_gram1_res:
                c = float(0.5)/float(self.training_gram1_res[v1])
            else:
                pass
        return c

    def write_result(self):
        result_file = open(self.result_file_path, 'w')
        for i in self.result_list:
            result_file.writelines(i+'\n')
        result_file.close()


if __name__ == '__main__':
    mynlp()

测试正确率源代码

# encoding=utf-8
l1=[]
l2=[]

file = open('result.txt')
for i in file:
    l1.append(i)
file.close()

file1 = open('Test_Data/development_set_answers.txt')
for i in file1:
    l2.append(i)
file1.close()
c = 0
for i in range(len(l1)):
    if l1[i] == l2[i]:
        c += 1
# c 代表正确的数目

print '结果:正确数目:'+str(c)+' 总共题目:'+str(len(l1))+' 正确率:'+str(float(c)/float(len(l1)))

完整项目

https://download.csdn.net/download/kangyucheng/10504044



猜你喜欢

转载自blog.csdn.net/Kangyucheng/article/details/80771847