当前位置:   article > 正文

宗成庆《自然语言理解》第5章作业_利用汉语切分和标注语料(注意版权的合法性),实现基于 ngram 的汉语自动分词方

利用汉语切分和标注语料(注意版权的合法性),实现基于 ngram 的汉语自动分词方

5-2. 利用汉语切分和标注语料(注意版权的合法性),尝试用bi-gram 实现一个简单的汉语自动分词程序。

  1. #-------------------------------------------------------------------------------
  2. # Name: n_gram切分中文
  3. # Purpose: 自然语言处理第5章作业
  4. # 水平有限,仅做参考
  5. # Author: nkenen
  6. #
  7. # Created: 22/02/2020
  8. # Copyright: (c) Administrator 2020
  9. # Licence: <your licence>
  10. #-------------------------------------------------------------------------------
  11. import re
  12. symbol = ',.!?。,?!0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
  13. #本程序并不是有用的只是将已标注好的1998语料库给转变成无标注的
  14. def Makenomarkedcorpus():
  15. file = open('F:/自然语言处理/1980pd.txt','w',encoding='utf-8')
  16. filer = open('F:/自然语言处理/199801_people_s_daily.txt','r',encoding='utf-8',errors='ignore')
  17. for line in filer:
  18. str = ''
  19. flag = 0
  20. i=0
  21. while i < len(line):
  22. if line[i] == '/':
  23. while line[i] != ' ' :
  24. i += 1
  25. if i >= len(line):
  26. break
  27. elif line[i] == ']':
  28. str += ']'
  29. flag = 1
  30. elif flag == 1:
  31. str += line[i]
  32. i += 1
  33. file.write(str+'\n')
  34. file.close()
  35. filer.close()
  36. #如何切分总步骤
  37. #第一步导入语料库
  38. #第二步列出所有切分可能的句子
  39. #第三步将已切分的句子在语料库以n-gram求最大概率
  40. #语料库类
  41. class Corpus(object):
  42. def __init__(self):
  43. self.content = ''
  44. self.size = 0
  45. #导入语料库
  46. def loadlib(self,path):
  47. with open(path,'r',encoding='utf-8',errors='ignore')as file:
  48. self.content = str(file.readlines())
  49. self.size = len(self.content)
  50. #ngram语法
  51. class N_gram(object):
  52. def __init__(self,N,corpus):
  53. self.N = N
  54. self.corpus = corpus.content
  55. self.problist = []
  56. #计算句子概率,历史已有n个字出现wi的概率p(wi|wi-1。。。wi-n-1)的连乘
  57. def ComputeProb(self,entlist):
  58. for sen in entlist:
  59. lst = sen.split(" ")
  60. lens = len(lst)
  61. prob = 1.0
  62. if self.N > 1:#本次运算中可能语料库或者算法问题,起始>2-gram输出的概率相同,可能我水平还不够
  63. prob *= (self.corpus.count(lst[0])+1)/len(self.corpus)#加1平滑,懒得写算法比较难的
  64. for i in range(1,len(lst)):
  65. strh = ''
  66. stra = ''
  67. k = 0
  68. if i <= self.N:
  69. k = 0
  70. else:
  71. k = i - self.N
  72. for j in range(k,i):#找到前面的n个历史,可能少于n
  73. strh += lst[j]+' '
  74. stra = strh + lst[i]
  75. #print(stra)
  76. #概率p(wi|wi-1。。。wi-n-1)的连乘
  77. #prob *= (self.corpus.count(stra)+1)/(self.corpus.count(strh))#这个连乘算法有问题,分母可能出现0,直接让分母为语料库的大小
  78. prob *= (self.corpus.count(stra)+1)/len(self.corpus)
  79. else:
  80. for i in range(len(lst)):
  81. prob *= (self.corpus.count(lst[i])+1)/len(self.corpus)
  82. self.problist.append(prob)
  83. print(dict(zip(entlist,self.problist)))
  84. #找到最大概率
  85. def findBiggestP(self,entlist):
  86. max =0.0
  87. index = 0
  88. for i in range(len(self.problist)):
  89. if max < self.problist[i]:
  90. max = self.problist[i]
  91. index = i
  92. print([str(entlist[index]),max])
  93. return str(entlist[index]),max
  94. def clearplst(self):
  95. self.problist.clear()
  96. class Segmentation(object):
  97. def __init__(self,content,corpus):
  98. self.content= content
  99. self.entlist = []
  100. self.endindex = 0
  101. self.worddict = corpus.content
  102. self.n_gram = N_gram(2,corpus)
  103. def loadContent(self,path):
  104. with open(path,'r',encoding='utf-8',errors='ignore')as file:
  105. self.content = str(file.readlines())
  106. def processSeg(self):
  107. strA = ''
  108. seg_suc_str = ''
  109. prob_suc = 1.0
  110. global symbol
  111. for word in self.content:
  112. if word in symbol:
  113. #这里进行切分
  114. self.entlist.clear()
  115. self.endindex = 0
  116. self.n_gram.clearplst()
  117. #第二步列出所有切分可能的句子
  118. self.__findAllSentence(strA)
  119. #计算所有句子概率
  120. if len(strA) >1:
  121. self.n_gram.ComputeProb(self.entlist)
  122. #切分完成后加上后面的符号继续
  123. strA,prob = self.n_gram.findBiggestP(self.entlist)
  124. prob_suc *= prob
  125. #else:没计算符号数字出现的概率
  126. #prob *= (self.corpus.count(word)+1)/len(len(self.corpus))
  127. if strA != '':#当不是字符或单个字符多加个空格用于标示切分
  128. strA += ' '
  129. seg_suc_str += strA + word + ' '
  130. strA = ''
  131. prob = 0
  132. elif word not in '\n\t\r':
  133. strA += word
  134. return seg_suc_str,prob_suc
  135. def __findAllSentence(self,strA):
  136. #将所有的单词切分出来,然后切格式是【word,start,stop】
  137. exword = self.__findExistofword(strA)
  138. if exword != [] and exword != None:
  139. for i in range(len(exword)):#此循环很重要,找到所有起始点0的字或词语
  140. if exword[i][1] == 0:#找到起始点0
  141. self.endindex = 0
  142. strs = exword[i][0]
  143. #下面是递归遍历所有可能的节点,跟树节点很像
  144. self.__findSentence(exword,strs,i,len(strA))
  145. print(self.entlist)
  146. #找出所有在语料库出现的字词,语料库是已经切分好的
  147. def __findExistofword(self,strA):
  148. if len(strA) <= 1:
  149. return
  150. exword = []
  151. for i in range(len(strA)):
  152. for j in range(i+1,len(strA)+1):
  153. if strA[i:j] in self.worddict:
  154. exword.append([strA[i:j],i,j])
  155. print('exword is ',exword)
  156. return list(exword)
  157. #此算法很重要,是将所有可能的句子找出来的算法
  158. def __findSentence(self,exword,strs,i,tlen):
  159. if self.endindex == tlen:#已经是最后的节点
  160. self.entlist.append(strs)
  161. return
  162. else:
  163. for j in range(i+1,len(exword)):
  164. if exword[i][2] == exword[j][1]:#是下一个连续的节点
  165. strs1 =strs + ' ' + exword[j][0]#构成句子,并切分
  166. self.endindex = exword[j][2]#记录本次节点
  167. #继续向下寻找
  168. self.__findSentence(exword,strs1,j,tlen)
  169. def main():
  170. path = 'F:/自然语言处理/1980pd.txt'
  171. #Makenomarkedcorpus()
  172. corpus = Corpus()
  173. corpus.loadlib(path)
  174. seg_str = '我正在学习自然语言处理!'
  175. segmentation = Segmentation(seg_str,corpus)
  176. seg_suc_str,prob_suc = segmentation.processSeg()
  177. print(seg_suc_str,prob_suc)
  178. pass
  179. if __name__ == '__main__':
  180. main()

参考:

https://blog.csdn.net/qijingpei/article/details/79330491

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/331309
推荐阅读