• Bigram-MLE语言模型和模拟输入法的python实现


    一、题目要求

     二、实验数据集

              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.语言模型的性能评估(准备测试集,计算交叉熵和困惑度)

  • 相关阅读:
    HTML颜色表
    grid
    DOM和BO
    注册表
    js 正则表达式
    python学习之路(一)
    python学习之路(三)
    python学习之路(二)
    自己编写的泛型集合类(其实是照着微软的List写的)
    客户端回调服务端无刷新事件
  • 原文地址:https://www.cnblogs.com/liweikuan/p/14244637.html
Copyright © 2020-2023  润新知