一、题目要求
二、实验数据集
https://github.com/liweikuan123/-.git
三、python代码
function.py(对语料进行处理,生成用于构建二元语言模型和模拟输入法的中间文件)
1 import re 2 import jsonlines 3 4 5 # 训练语料:metadata.txt 6 # 生成文档: 1. d.jsonl文件, 2. output.jsonl文件 3. generator_5possible_value.jsonl文件 4. data.txt文件 7 8 9 10 new_ll=[] #词汇表:存储单词 11 dict_file={} #cut函数中,对每一行数据切分后,产生的中间存储变量, 字典格式:dict{the:[boy,boy, girl,apple, apple,...], boy:[like,like, eat, play,play.....], like:[eatting, playing.....], eatting:[apple,apple.... ].....} 12 total_list=[] #全部单词(包含重复单词) 13 d={} #存储每个单词以及它的统计频数, d{read:13, the:10, a:12, book: 15,......... } 14 frequency_dict={} #用于封装key_value{}的中间存储变量。 15 key_value={} #在output.jsonl文件中按行存储的字典 16 ############################################################################################################### 17 key_5value={} #用于封装value{}的中间存储变量。 18 word_num=5 #每个单词后最可能出现的单词的数目。 19 value={} #generator_5possible_value.jsonl文件中按行存储的字典 20 21 22 23 #count_list()函数:用于统计词汇表中的单词 24 #new_ll中存储词汇表中的单词 25 def count_list(list_file): 26 #用一个列表记录总共多少种单词 27 global new_ll 28 for i in list_file: 29 if i not in new_ll: 30 new_ll.append(i) 31 32 33 34 #存储字典d (字典中包含键值对,例如:{read:13, the:10, a:12, book: 15,......... },生成d.jsonl文件。 35 def save_dict(line): 36 with jsonlines.open('i:d.jsonl', mode='w') as writer: 37 writer.write(line) 38 39 40 41 #遍历total_list列表,对列表中的单个单词进行统计数目,将结果存入d[]字典内,例如:d{ read : 20, the : 30,....} 42 def count_total_list(total_list): 43 #用一个字典记录结果 ,遍历列表 , 求count() 44 global new_ll 45 for i in new_ll: 46 d[i]=total_list.count(i) #统计某个单词在训练语料中出现的频数。 47 save_dict(d) #存储d字典 48 49 50 51 #对一行数据进行切分,例如:the boy like eatting apple, 切分为:{the:[boy], boy:[like], like:[eatting], eatting:[apple].......} 52 #如果dict_file中存在某一个key=result_list[i],将result_list[i+1]添加到dict_file[result_list[i]]的列表中。 53 #构建dict_file字典,字典最终格式:dict{the:[boy,boy, girl,apple, apple,...], boy:[like,like, eat, play,play.....], like:[eatting, playing.....], eatting:[apple,apple.... ].....} 54 def cut(result_list): 55 global dict_file 56 for i in range(len(result_list)-1): 57 if result_list[i] not in dict_file: 58 dict_file[result_list[i]]=[result_list[i+1]] 59 else: 60 dict_file[result_list[i]].append(result_list[i+1]) 61 62 63 #对frequency_count()函数产生的key_value{}进行存储。 64 #以json格式按行存储字典元素(字典元素中包含键值对,每条json数据格式:key_value{read :{ the:10, a:12, book: 15 } } ,即以read开头的,二元语法及频数。 65 #生成output.jsonl文件 66 def save_key_value(line): 67 with jsonlines.open('i:output.jsonl', mode='a') as writer: 68 writer.write(line) 69 70 71 72 #对new_ll(词汇表)中各个单词,挑选其后最可能出现的五个单词,生成generator_5possible_value.jsonl文件, 用于模拟输入法程序。 73 #value字典的格式形式: value { the:30, a:20, book:15, pen:12, apple:2} 74 def generator_5possible_value(i,data): 75 global value,key_5value 76 data_list = list(data.keys()) 77 length = len(data_list) 78 if length < word_num: 79 for count in range(length): 80 value[data_list[count]]=data[data_list[count]] 81 key_5value[i]=value 82 else: 83 for count in range(word_num): 84 value[data_list[count]] = data[data_list[count]] 85 key_5value[i] = value 86 with jsonlines.open('i:generator_5possible_value.jsonl', mode='a') as writer: 87 writer.write(key_5value) #生成generator_5possible_value.jsonl文件,存储每个单词后最有可能出现的五个单词。 88 key_5value={} #用于封装value{}的中间存储变量。 89 value={} 90 91 92 93 94 #对于new_ll中的每一个单词,例如:read,查看是否在dict_file字典中存在key==i,如果存在,对于dict_file[i]中每个j,构建frequency_dict[name]=key,其中name=str(j),key=dict_file[i].count(j) 95 #对 frequency_dict中的对象,按照频数排序。 96 #再对frequency_dict进行封装,即:key_value[i]=data 97 #最终key_value字典格式为:key_value{read: {the:10, a:12, book:5,....} } 及二元语法中,read后出现的单词,以及各自的频数。 98 def frequency_count(): 99 global key_value,frequency_dict,new_ll 100 for i in new_ll: #new_ll中每个单词 101 if i in dict_file: #判断是否在dict_file中存在key==i 102 for j in dict_file[i]: 103 name=str(j) 104 key=dict_file[i].count(j) 105 frequency_dict[name]=key 106 107 data=dict(sorted(frequency_dict.items(), key=lambda d: d[1], reverse=True))#对 frequency_dict中的对象,按照频数排序。 108 # print(data) 109 key_value[i] =data #对frequency_dict进行封装 110 generator_5possible_value(i,data) #对new_ll中各个单词,挑选其后最可能出现的五个单词 111 save_key_value(key_value) #对分装好的key_value进行存储 112 frequency_dict={} 113 key_value = {} 114 # frequency.append(frequency_dict) 115 # frequency_dict = {} 116 117 118 119 120 def main(): 121 with open('i:metadata.txt',"r",encoding='utf-8') as f: #设置文件对象 122 with open('i:data.txt', 'w') as out: 123 for line in f.readlines(): # 依次读取每行 124 str_ =str(line) 125 # print(str_) 126 str_=str_[::-1] 127 count=str_.find("|") 128 # print(str_) 129 # print(count) 130 str_=str_[0:count] 131 str_=str_[::-1] 132 result_list = re.findall('[a-zA-Z0-9]+', str_) 133 134 result_list.insert(0,"BOS") 135 result_list.append("EOS") 136 #以上两行代码,对metadata.txt中第三列的每个句子处理为格式:result_list[ 'BOS','the','boy','is','a','very','great','child','EOS'] 137 for i in result_list: 138 total_list.append(i)#统计所有单词,包括重复单词。 139 # print(result_list) 140 count_list(result_list) 141 cut(result_list) 142 out.writelines(result_list) #生成data.txt文件,文件中储存处理后的句子,每个句子处理为格式:result_list[ 'BOS','the','boy','is','a','very','great','child','EOS']。 143 out.writelines(" ") 144 # 以上部分代码,负责对metadata.txt中第三列进行处理,total_list中存储切分后的所有单词(包括重复单词). 145 count_total_list(total_list) #遍历total_list列表,对列表中的单个单词进行统计数目,将结果存入d[]字典内,例如:d{ read : 20, the : 30,....} 146 print("字典"+str(d)) 147 print(len(d)) 148 frequency_count() #生成key_value字典, 最终key_value字典格式为:key_value{read: {the:10, a:12, book:5,....} } 及二元语法中,read后出现的单词,以及各自的频数。 149 print("字符" + str(new_ll)) 150 print(len(new_ll)) 151 print("键-值" + str(dict_file)) 152 print(len(dict_file)) 153 print(len(total_list)) 154 out.close() 155 f.close() 156 157 158 159 160 if __name__ == "__main__": 161 main()
LanguageModel.py(Bigram-MLE语言模型和模拟输入法程序)
1 import jsonlines 2 3 d={} #用于接收d.jsonl文件中的d{}字典 4 copy_data=[] #用于接收generator_5possible_value.jsonl文件中的value{}字典 5 sentence={} #用于存储输入句子的最终处理结果的字典 6 probability_key_value={} #用于存储句子[the first time]中二元语法的概率,例如:格式 {BOS-the:0.028100, the-first:0.009096, first-time:0.034375, time-EOS:0.110638} 7 8 9 #init_data()函数 10 #进行数据初始化,导入d.jsonl文件和generator_5possible_value.jsonl文件。 11 def init_data(): 12 global d,copy_data 13 with jsonlines.open('i:d.jsonl', "r") as dict_reader: 14 for line in dict_reader: #d{}字典在d.json文件中,实际上存储在一个json文件中,此循环只执行一次。 15 d = line 16 with jsonlines.open('i:generator_5possible_value.jsonl',"r") as reader: 17 for obj in reader: #在generator_5possible_value.jsonl文件中,存在多个value{}字典,value{}字典的个数等于new_ll(词汇表)中单词的数目,循环执行多次。 18 copy_data.append(obj) 19 20 21 22 #find()函数的功能 23 #对于一个二元语法模型<read a>,计算p(a|read)=c(read a)/c(read),返回计算结果 24 def find(key,value): 25 global copy_data 26 for i in copy_data: 27 if key in i: 28 if value in i[key]: 29 return i[key][value] 30 else: 31 return 0 32 33 34 35 #Bigram-MLE模型算法 36 def algorithm_Bigram(data): 37 global sentence,d,probability_key_value 38 probability=1 #存储句子概率的中间变量。 39 40 output=data.split() 41 output.insert(0,"BOS") 42 output.append("EOS") 43 #上面三行代码,对输入的句子进行处理。 例如:句子[ i am a student ]处理结果为['BOS','i','am','a','student','EOS'] 44 for i in range(len(output)-1): 45 sentence[output[i]]=output[i+1] #处理后格式:sentence{ BOS:i , i:am, am:a, a:student, student:EOS} 46 for j in range(len(output)-1): 47 try: 48 value= find(output[j],output[j+1])/d[output[j]] 49 except ZeroDivisionError: 50 value=-1 51 print("不存在"+str(output[j])) 52 probability_key_value[str(output[j])+'-'+str(output[j+1])]=value 53 print(probability_key_value) 54 probability*=value 55 # print(sentence) 56 # print(output) 57 return probability 58 59 60 61 62 63 #模拟输入法:给定一个单词推荐接下来最有可能输入的5个单词。 64 def algorithm_IME(data): 65 global copy_data 66 for dict_data in copy_data: 67 if data in dict_data: 68 print(dict_data[data]) 69 # print(i) 70 # data2 = json.dumps(history, sort_keys=True, indent=4, separators=(',', ': ')) 71 # print(data2) 72 73 74 75 76 77 def main(): 78 init_data() 79 # print(copy_data) 80 # print(len(copy_data)) 81 select = input("Bigram-MLE计算语句概率未使用平滑技术(输入1) 模拟输入法(输入2)请输入选择: ") 82 if select=='1': 83 print("Bigram-MLE计算语句概率未使用平滑技术") 84 data = input("请输入: ") 85 probability=algorithm_Bigram(data) 86 print(probability) 87 print("结束") 88 if select=='2': 89 print("模拟输入法") 90 while True: 91 data = input ("请输入: ") 92 if data=='#': 93 break 94 print("你输入的内容是: ", data) 95 algorithm_IME(data) 96 print("结束") 97 98 99 100 if __name__ == "__main__": 101 main()
四、可能的改进
语言模型概率:
1.概率科学计数
为了防止概率计算的时候因为越算越小导致计算机无法比较,所有的概率都进行了自然对数运算
2.引入平滑技术
3.语言模型的性能评估(准备测试集,计算交叉熵和困惑度)