Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

隐马尔可夫词性标注概率转移矩阵问题 #434

Closed
530154436 opened this issue Mar 14, 2017 · 13 comments
Closed

隐马尔可夫词性标注概率转移矩阵问题 #434

530154436 opened this issue Mar 14, 2017 · 13 comments

Comments

@530154436
Copy link

你好,博主大人,这里在统计标签出现次数时是不是会重复计算呢?而且也无法保证了概率转移矩阵每行元素之和等于1呢?我感觉 total[j] += matrix[i][j];这句有重复计算的可能。
// 需要统计一下每个标签出现的次数 total = new int[ordinaryMax]; for (int j = 0; j < ordinaryMax; ++j) { total[j] = 0; for (int i = 0; i < ordinaryMax; ++i) { total[j] += matrix[i][j]; total[j] += matrix[j][i]; } }

@hankcs
Copy link
Owner

hankcs commented Mar 20, 2017

的确,我仔细算了一下,发现你说的是对的。当时只想着省点空间,没有专门去统计每个tag出现的频次。以后会修复这个表格的,谢谢!

@530154436
Copy link
Author

@hankcs 感谢回复,最近拜读大神源码,太赞了!

@hankcs
Copy link
Owner

hankcs commented Mar 20, 2017

转移矩阵的频次统计新方法

比如对于ABBAAB这个标注序列来讲,转移矩阵如下:

A B
A 1 2
B 1 1

仅仅逐行累计的话,A的频次为1+2=3,B的频次为1+1=2。我们会发现B的频次少了一个。这是因为B曾经作为句子结尾出现过一次。也就是说,如果标签X出现在句子结尾n次,那么该算法会导致X少算n个频次。
幸运的是,HanLP中的句子结尾是有专门的end标签的,受影响的只有end标签(为0)。更幸运的是,如果对end按列累计,即统计转移到end的次数,则恰好能还原end的频次。
推广开来,在有固定的表示句子结尾的标签的情况下,如果某标签按行统计频次为0,则按列统计即可,问题解决。

@yuanlisky
Copy link

yuanlisky commented Apr 1, 2017

hankcs你好,你的修改方式好像只对核心词典有用,在实体识别中,地名和机构名的结尾标签是B,这时候计算出来的频次统计是不准确的(虽然和实际频次差距可能不是很大),我想还是需要每个tag出现的频次表格。
还有初始状态概率矩阵的问题,根据你的计算代码
start_probability[s] = -Math.log(frequency / totalFrequency)
求的是s状态出现的概率,但是根据定义,初始状态概率矩阵表示的是t=1时刻,状态处于s的概率。
举个例子,就像四元标注'BMES'中,它的初始状态概率为
P={'B': 0.7689828525554734, 'E': 0, 'M': 0, 'S': 0.2310171474445266}
这里EM在t=1时刻出现的概率为0,与实际相符。
所以我认为这里不能单纯的使用频次除以总词频的算法,可能需要根据你的训练语料,统计句首词语出现的状态,再除以样本数?

@hankcs
Copy link
Owner

hankcs commented Apr 7, 2017

我赞同简化问题,加一个tag频次表。
对标签B的不准确性,你能举个例子吗?目前地词语结尾多数是E,机构名的结尾多数是D,还有其他的情况,但不是B。另外,我上面说的结尾指的是句子的结尾,不是词语结尾。

@hankcs
Copy link
Owner

hankcs commented Apr 7, 2017

第二个问题你说得对,初始状态概率的估计应该为N个样本中初始状态为s的频次除以N。这段代码写得太早,当时没有想清楚,应该参考:http://www.hankcs.com/ml/hidden-markov-model.html#h2-13

太感谢了,修复工作加入开发日志。

@yuanlisky
Copy link

yuanlisky commented Apr 10, 2017

关于上面《转移矩阵的频次统计新方法》,解决的方案是基于句子的结尾标签是专有的,标签为'end',也就是说,‘end’行肯定是为0的,那么当某一行的和为0时,就能断定这是标签'end'的行,要计算end出现次数则要对'end'的列相加。
但是在实体识别的字典中,比如地名识别'ns.txt'和机构识别'nt.txt'的句子结尾标志'末##末‘的标签都是'B',但是这个标签'B'并不是句子结尾独有的,那么你计算句末标签出现次数的前提,判断某一行的和为0,这种情况并不会出现。

@yuanlisky
Copy link

yuanlisky commented Apr 10, 2017

第二个问题,初始状态概率。
我再想了一下,发现词典中有专门用于标记句子开头的标志'始##始',那么根据定义,初始状态概率是不是可以根据'始##始'的标签来计算。比如在核心词典中,'始##始'的标签为‘begin’,并为其独有,那么:
初始状态概率P={'begin': 1, 'nt': 0, 'nr': 0, 'zg': 0,...},表示初始状态的标签肯定为'begin'。
那么对于其它词典,比如地名识别'nt.txt'中,句子开头的标签为"始##始 S 1139590 A 23975",那么初始状态概率P={'S': 1139590/(1139590+23975),
'A': 23975/(1139590+23975),
'B': 0,
'C': 0,
...}

@hankcs
Copy link
Owner

hankcs commented Apr 13, 2017

第一个问题确实如此,当时总想着省,没想清楚。
第二个问题初始状态概率的确不需要,第一个标签一定是句子开头“S”。

        // 第一个是确定的
        tagList.add(pre);

关于始##始A标签,它也来源于无心的错误:

受限于语料成本,当时地名识别的语料是利用程序自动转换的。
A标签代表地名的上文,当一个地名作为句子的第一个词时,程序自动将始##始S转换为A标签。
所以目前最大限度的修正方案为把始##始的A频次合并到S频次中去(当然转移概率也会受到无法修复的牵连)。

@yuanlisky
Copy link

嗯。那目前就先这样修正吧,转移频率的问题可能需要在以后的版本中更新语料标签转换的程序吧

@hankcs
Copy link
Owner

hankcs commented Apr 20, 2017

是的。

@xinfeng1i
Copy link

请问,关于初始概率计算的问题,在目前的版本1.7.3中已经解决了吗?
我看到关于转移矩阵的计算问题,在版本1.2.9中已经修复了,不过逻辑感觉比较绕。

@hankcs
Copy link
Owner

hankcs commented Jun 22, 2019

请问,关于初始概率计算的问题,在目前的版本1.7.3中已经解决了吗?
我看到关于转移矩阵的计算问题,在版本1.2.9中已经修复了,不过逻辑感觉比较绕。

刚才修复了。HMM的优雅实现请参考 https://github.com/hankcs/HanLP/blob/master/src/main/java/com/hankcs/hanlp/model/hmm/HMMPOSTagger.java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants