分词 算法依据“10.4.2 维特比算法” :param artical:要分词的文章 :param PI: 初始状态概率向量PI :param A: 状态转移矩阵 :param B: 观测概率矩阵 :return: 分词后的文章
(artical, PI, A, B)
| 162 | return artical |
| 163 | |
| 164 | def participle(artical, PI, A, B): |
| 165 | ''' |
| 166 | 分词 |
| 167 | 算法依据“10.4.2 维特比算法” |
| 168 | :param artical:要分词的文章 |
| 169 | :param PI: 初始状态概率向量PI |
| 170 | :param A: 状态转移矩阵 |
| 171 | :param B: 观测概率矩阵 |
| 172 | :return: 分词后的文章 |
| 173 | ''' |
| 174 | #初始化分词后的文章列表 |
| 175 | retArtical = [] |
| 176 | |
| 177 | #对文章按行读取 |
| 178 | for line in artical: |
| 179 | #初始化δ,δ存放四种状态的概率值,因为状态链中每个状态都有 |
| 180 | #四种概率值,因此长度时该行的长度 |
| 181 | delta = [[0 for i in range(4)] for i in range(len(line))] |
| 182 | #依据算法10.5 第一步:初始化 |
| 183 | for i in range(4): |
| 184 | #初始化δ状态链中第一个状态的四种状态概率 |
| 185 | delta[0][i] = PI[i] + B[i][ord(line[0])] |
| 186 | #初始化ψ,初始时为0 |
| 187 | psi = [[0 for i in range(4)] for i in range(len(line))] |
| 188 | |
| 189 | #算法10.5中的第二步:递推 |
| 190 | #for循环的符号与书中公式一致,可以对比着看来理解 |
| 191 | #依次处理整条链 |
| 192 | for t in range(1, len(line)): |
| 193 | #对于链中的米格状态,求四种状态概率 |
| 194 | for i in range(4): |
| 195 | #初始化一个临时列表,用于存放四种概率 |
| 196 | tmpDelta = [0] * 4 |
| 197 | for j in range(4): |
| 198 | # 计算第二步中的δ,该部分只计算max内部,不涉及后面的bi(o) |
| 199 | # 计算得到四个结果以后,再去求那个max即可 |
| 200 | # 注:bi(Ot)并不在max的式子中,是求出max以后再乘b的 |
| 201 | # 此外读者可能注意到书中的乘法在这里变成了加法,这是由于原先是概率 |
| 202 | # 直接相乘,但我们在求得概率时,同时取了log,取完log以后,概率的乘法 |
| 203 | # 也就转换为加法了,同时也简化了运算 |
| 204 | # 所以log优点还是很多的对不? |
| 205 | tmpDelta[j] = delta[t - 1][j] + A[j][i] |
| 206 | |
| 207 | #找到最大的那个δ * a, |
| 208 | maxDelta = max(tmpDelta) |
| 209 | #记录最大值对应的状态 |
| 210 | maxDeltaIndex = tmpDelta.index(maxDelta) |
| 211 | |
| 212 | #将找到的最大值乘以b放入, |
| 213 | #注意:这里同样因为log变成了加法 |
| 214 | delta[t][i] = maxDelta + B[i][ord(line[t])] |
| 215 | #在ψ中记录对应的最大状态索引 |
| 216 | psi[t][i] = maxDeltaIndex |
| 217 | |
| 218 | #建立一个状态链列表,开始生成状态链 |
| 219 | sequence = [] |
| 220 | #算法10.5 第三步:终止 |
| 221 | #在上面for循环全部结束后,很明显就到了第三步了 |