依据训练文本统计PI、A、B :param fileName: 训练文本 :return: 三个参数
(fileName)
| 22 | import time |
| 23 | |
| 24 | def trainParameter(fileName): |
| 25 | ''' |
| 26 | 依据训练文本统计PI、A、B |
| 27 | :param fileName: 训练文本 |
| 28 | :return: 三个参数 |
| 29 | ''' |
| 30 | #定义一个查询字典,用于映射四种标记在数组中对应的位置,方便查询 |
| 31 | # B:词语的开头 |
| 32 | # M:一个词语的中间词 |
| 33 | # E:一个词语的结果 |
| 34 | # S:非词语,单个词 |
| 35 | statuDict = {'B':0, 'M':1, 'E':2, 'S':3} |
| 36 | |
| 37 | #每个字只有四种状态,所以下方的各类初始化中大小的参数均为4 |
| 38 | #初始化PI的一维数组,因为对应四种状态,大小为4 |
| 39 | PI = np.zeros(4) |
| 40 | #初始化状态转移矩阵A,涉及到四种状态各自到四种状态的转移,因为大小为4x4 |
| 41 | A = np.zeros((4, 4)) |
| 42 | #初始化观测概率矩阵,分别为四种状态到每个字的发射概率 |
| 43 | #因为是中文分词,使用ord(汉字)即可找到其对应编码,这里用一个65536的空间来保证对于所有的汉字都能 |
| 44 | #找到对应的位置来存储 |
| 45 | B = np.zeros((4, 65536)) |
| 46 | #去读训练文本 |
| 47 | fr = open(fileName, encoding='utf-8') |
| 48 | |
| 49 | #文本中的每一行认为是一个训练样本 |
| 50 | #在统计上,三个参数依据“10.3.2” Baum-Welch算法内描述的统计 |
| 51 | #PI依据式10.35 |
| 52 | #A依据10.37 |
| 53 | #B依据10.38 |
| 54 | #注:并没有使用Baum-Welch算法,只是借助了其内部的三个参数生成公式,其实 |
| 55 | #公式并不是Baum-Welch特有的,只是在那一节正好有描述 |
| 56 | for line in fr.readlines(): |
| 57 | #---------------------训练集单行样例-------------------- |
| 58 | #深圳 有 个 打工者 阅览室 |
| 59 | #------------------------------------------------------ |
| 60 | #可以看到训练样本已经分词完毕,词语之间空格隔开,因此我们在生成统计时主要借助以下思路: |
| 61 | # 1.先将句子按照空格隔开,例如例句中5个词语,隔开后变成一个长度为5的列表,每个元素为一个词语 |
| 62 | # 2.对每个词语长度进行判断: |
| 63 | # 如果为1认为该词语是S,即单个字 |
| 64 | # 如果为2则第一个是B,表开头,第二个为E,表结束 |
| 65 | # 如果大于2,则第一个为B,最后一个为E,中间全部标为M,表中间词 |
| 66 | # 3.统计PI:该句第一个字的词性对应的PI中位置加1 |
| 67 | # 例如:PI = [0, 0, 0, 0],当本行第一个字是B,即表示开头时,PI中B对应位置为0, |
| 68 | # 则PI = [1, 0, 0, 0],全部统计结束后,按照计数值再除以总数得到概率 |
| 69 | # 统计A:对状态链中位置t和t-1的状态进行统计,在矩阵中相应位置加1,全部结束后生成概率 |
| 70 | # 统计B:对于每个字的状态以及字内容,生成状态到字的发射计数,全部结束后生成概率 |
| 71 | # 注:可以看一下“10.1.1 隐马尔可夫模型的定义”一节中三个参数的定义,会有更清晰一点的认识 |
| 72 | #------------------------------------------------------- |
| 73 | #对单行句子按空格进行切割 |
| 74 | curLine = line.strip().split() |
| 75 | #对词性的标记放在该列表中 |
| 76 | wordLabel = [] |
| 77 | #对每一个单词进行遍历 |
| 78 | for i in range(len(curLine)): |
| 79 | #如果长度为1,则直接将该字标记为S,即单个词 |
| 80 | if len(curLine[i]) == 1: |
| 81 | label = 'S' |