fxsjy / jieba

结巴中文分词

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

模型的数据是如何生成的?

mtejiang opened this issue · comments

就是finalseg/prob_*.py中的这些数据

@feriely , 来源主要有两个,一个是网上能下载到的1998人民日报的切分语料还有一个msr的切分语料。另一个是我自己收集的一些txt小说,用ictclas把他们切分(可能有一定误差)。 然后用python脚本统计词频。

要统计的主要有三个概率表:1)位置转换概率,即B(开头),M(中间),E(结尾),S(独立成词)四种状态的转移概率;2)位置到单字的发射概率,比如P("和"|M)表示一个词的中间出现”和"这个字的概率;3) 词语以某种状态开头的概率,其实只有两种,要么是B,要么是S。

比如finalseg/prob_trans.py这个文件:

{'B': {'E': 0.8518218565181658, 'M': 0.14817814348183422},
'E': {'B': 0.5544853051164425, 'S': 0.44551469488355755},
'M': {'E': 0.7164487459986911, 'M': 0.2835512540013088},
'S': {'B': 0.48617017333894563, 'S': 0.5138298266610544}}

P(E|B) = 0.851, P(M|B) = 0.149,说明当我们处于一个词的开头时,下一个字是结尾的概率要远高于下一个字是中间字的概率,符合我们的直觉,因为二个字的词比多个字的词更常见。

应该把这个写入wiki

BMES法是从BE改进的,M$又用到了BB1B2MES 6元法。 state越多效果越好。
但我感觉state还是不够。只用几个state是把大量样本信息模糊化了, 反过来用viterbi估计分词,是去马赛克,效果不会多好。为什么不用更多的states呢?自然理解的话,O:sentence。 States:word_cut。 这样state数是2*汉字个数。
e.g.:
X:我们|在|哈尔滨|
Y:我 们在哈尔滨

我用icwb2-data/gold/pku_test_gold.utf8训练,对比BMES 和word state的分词效果:

BMES: 改判|被|告人|死刑|立即|执行|
WORD: 改判|被告人|死刑|立即|执行|
BMES: 检察院|鲍|绍坤|检察长|
WORD: 检察院|鲍|绍坤|检察长|
BMES: 小明|硕士|毕业|于|**|科学院|计算|所|
WORD: 小明|硕士|毕业|于|**|科学院|计算所|
BMES: 工信|处女|干事|每月|经过|下属|科室|都|要|亲口|交代24口|交换|机等|技术|性器|件|的|安装|工作|
WORD: 工信|处女|干事|每月|经过|下属|科|室|都|要|亲|口|交代|24口|交换|机|等|技术性|器|件|的|安装|工作|

可见后者效果好一些。

@whille , 没有看太明白,你的建议是用更多的状态? 但是加状态回导致分词速度变得更慢哦,毕竟是纯python实现。

慢一些,但一个ob只有两个state对应, 比如ob['工']的state只有'工_'和‘工|'两种。所以迭代时可以continue。如果利用反向dict查找,就更快了。

另外想问一下,BMES看来是统计training得到的。之前看HMM的前向-后向算法,不知道是不是可以用来迭代的更新这个model。

@whille , 状态多一些使得分词更准确这一点我也赞同。其实,在jieba分词的词性标注子模块posseg中,就是将BMES四种状态和20集中词性做笛卡尔集得到所有的状态,最后的效果也的确比finalseg要好,尤其是人名识别方面,但是速度就严重下降了。https://github.com/fxsjy/jieba/blob/master/jieba/posseg/prob_start.py

感觉训练语料库还是比较小,对于web文本处理效果难免出现较多badcase,可否引入更多web真实文本训练?比如web网页、输入法细胞词库、wiki、问答网站的问题(相当于query)等

@fandywang , 现在的确存在这个问题。如果你看看dict.txt,随处可以看见一些不像词的词,高质量的训练数据不好搞啊。

@fxsjy 谢谢你的回答,这样看来是缺少现代的词库?我想做一个语义树,主要担心一些网络流行语、学术名词的匹配,还没有做这样的词库,看来我可以找时间补充一下

中文就是分词蛋疼。一直没有较好的朗读解决方案。

sogou有一个互联网词库 和中文词语搭配库 http://www.sogou.com/labs/dl/w.html ,不知道这个词库质量怎么样?能否添加进来。

@chundong , 可以加入,结巴支持自定义词典,只要按照格式就可以。

请问中文的trie树是怎么实现的,中文词语的首字可以有成千上万种选择,怎么解决的呢?

在python里面就是一个嵌套的dict实现。
在c++里面就是一个hash_map的实现。
成千上万又不是一个大数目,没什么难解决的吧。

@rav009

wuyanyi09@gmail.com

发件人: rav009
发送时间: 2013-09-30 17:20
收件人: fxsjy/jieba
主题: Re: [jieba] 模型的数据是如何生成的? (#7)
请问中文的trie树是怎么实现的,中文词语的首字可以有成千上万种选择,怎么解决的呢?

Reply to this email directly or view it on GitHub.

个人觉得TRIE树占用很大的内存,一级一级的dict下来内存用得不小啊。不知道有谁亲自测试用大字典的时候耗了多少内存不?
可以不用TRIE树,用一个小循环就可以搞定,慢一点感觉影响不特别大。

2013/9/30 Wu Yanyi notifications@github.com

在python里面就是一个嵌套的dict实现。
在c++里面就是一个hash_map的实现。
成千上万又不是一个大数目,没什么难解决的吧。

wuyanyi09@gmail.com

发件人: rav009
发送时间: 2013-09-30 17:20
收件人: fxsjy/jieba
主题: Re: [jieba] 模型的数据是如何生成的? (#7)
请问中文的trie树是怎么实现的,中文词语的首字可以有成千上万种选择,怎么解决的呢?

Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHubhttps://github.com//issues/7#issuecomment-25347223
.

@janson
1.我的线上cppjieba程序跑着看到内存占用百分比是个位数,没仔细看多少,但是就认为没有内存问题。
2.用map会省内存,但是速度不如hash_map,所以我用hash_map(因为1得知没有内存困扰)
4.个人认为trie树是暂时对这个分词最合适的数据结构了。你的小循环能否详细说一下。

wuyanyi09@gmail.com

发件人: janson
发送时间: 2013-09-30 17:55
收件人: fxsjy/jieba
抄送: Wu Yanyi
主题: Re: [jieba] 模型的数据是如何生成的? (#7)
个人觉得TRIE树占用很大的内存,一级一级的dict下来内存用得不小啊。不知道有谁亲自测试用大字典的时候耗了多少内存不?
可以不用TRIE树,用一个小循环就可以搞定,慢一点感觉影响不特别大。

2013/9/30 Wu Yanyi notifications@github.com

在python里面就是一个嵌套的dict实现。
在c++里面就是一个hash_map的实现。
成千上万又不是一个大数目,没什么难解决的吧。

wuyanyi09@gmail.com

发件人: rav009
发送时间: 2013-09-30 17:20
收件人: fxsjy/jieba
主题: Re: [jieba] 模型的数据是如何生成的? (#7)
请问中文的trie树是怎么实现的,中文词语的首字可以有成千上万种选择,怎么解决的呢?

Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHubhttps://github.com//issues/7#issuecomment-25347223
.


Reply to this email directly or view it on GitHub.

通过cpp上实现的话,TRIE可能占用比较小,这个我没有试过。但通过python的dict来实现TRIE树的话,占用内存挺大,我没有认真测试。但是当时我把jieba放到一个云平台运行的时候,就提示说内存占用过大被KILL掉了。所以我当时进行了以下的小修改:(这个修改是我今天重写的,没有很多测试)
def get_DAG(sentence):
WORD_MAX = 8
n = len(sentence)
i,j = 0,0
DAG = {}
while i < n:
for j in xrange(i, min(n,i+WORD_MAX), 1):
if sentence[i:j+1] in FREQ:
if not i in DAG:
DAG[i]=[]
DAG[i].append(j)
i += 1
j = i
for i in xrange(len(sentence)):
if not i in DAG:
DAG[i] =[i]
return DAG
把get_DAG函数改成以上函数。
以上函数只用到了FREQ,没有使用TRIE树。相比TRIE树,它的缺点是每i+1,都得进行8次的循环;若是TRIE树,会根据自身有的多少词来进行循环,稍微快一些。如果在搜索环境下使用的话,可以把WORD_MAX改成5或6就可以了。

2013/9/30 Wu Yanyi notifications@github.com

@janson
1.我的线上cppjieba程序跑着看到内存占用百分比是个位数,没仔细看多少,但是就认为没有内存问题。
2.用map会省内存,但是速度不如hash_map,所以我用hash_map(因为1得知没有内存困扰)
4.个人认为trie树是暂时对这个分词最合适的数据结构了。你的小循环能否详细说一下。

wuyanyi09@gmail.com

发件人: janson
发送时间: 2013-09-30 17:55
收件人: fxsjy/jieba
抄送: Wu Yanyi
主题: Re: [jieba] 模型的数据是如何生成的? (#7)
个人觉得TRIE树占用很大的内存,一级一级的dict下来内存用得不小啊。不知道有谁亲自测试用大字典的时候耗了多少内存不?
可以不用TRIE树,用一个小循环就可以搞定,慢一点感觉影响不特别大。

2013/9/30 Wu Yanyi notifications@github.com

在python里面就是一个嵌套的dict实现。
在c++里面就是一个hash_map的实现。
成千上万又不是一个大数目,没什么难解决的吧。

wuyanyi09@gmail.com

发件人: rav009
发送时间: 2013-09-30 17:20
收件人: fxsjy/jieba
主题: Re: [jieba] 模型的数据是如何生成的? (#7)
请问中文的trie树是怎么实现的,中文词语的首字可以有成千上万种选择,怎么解决的呢?

Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHub<
https://github.com/fxsjy/jieba/issues/7#issuecomment-25347223>
.


Reply to this email directly or view it on GitHub.


Reply to this email directly or view it on GitHubhttps://github.com//issues/7#issuecomment-25349446
.

@jannson , 很好的尝试。请问去掉TRIE之后,分词速度下降的多吗?

没有测试。有空我好好用cProfile来测试测试。

On Tue, Oct 8, 2013 at 9:40 AM, Sun Junyi notifications@github.com wrote:

@jannson https://github.com/jannson , 很好的尝试。请问去掉TRIE之后,分词速度下降的多吗?


Reply to this email directly or view it on GitHubhttps://github.com//issues/7#issuecomment-25859359
.

如果可以把字典文件分成几个,然后用mmap来加载可能可以避免内存问题

这么重要的问题居然在readme最后,这是要告诉大家一定要耐心看完readme吗?
感谢作者做出的工作!
不负责任的想象一下,如果有个最初始的分词器,只有一份最基本的词典,第一次只能使用trie来分词,分出词之后利用@fxsjy 说的训练hmm,之后都是trie树+viterbi分词,重复训练hmm,最后hmm中的各个参数会收敛吗?如果收敛得到的hmm是最佳的吗?

我试过,用 向前向后 迭代几次后,再用维特比解码,任何序列都会解码成 SSSSSSSS....
@lurga

@rav009 很好奇每次迭代解码的序列,想不明白为什么迭代几次后会成为SSSSSS

我随便测了几句 这应该跟初始概率的设置有关系 @lurga

commented

请问结巴里的trie树用的是原生的trie,没有用双数组优化吗?

@PhanYoung , 没有什么优化,就是dict嵌套dict实现的。

@fxsjy 请问位置转换概率中 BEMS 是怎么从字、词中分析出来的?我查找了网上大量资料,都没有对此有相关的介绍,一般都是给出词性。

分词后就有了,你知道这四个字母代表什么意思吧

发自我的 iPad

在 2014年5月25日,16:27,Yaoda Liu notifications@github.com 写道:

@fxsjy 请问位置转换概率中 BEMS 是怎么从字、词中分析出来的?我查找了网上大量资料,都没有对此有相关的介绍,一般都是给出词性。


Reply to this email directly or view it on GitHub.

谢谢!突然想明白了~
-- 
shonenada http://shonenada.com

开启 2014年5月25日 at 下午4:35:22, whille (notifications@github.com) 写:

分词后就有了,你知道这四个字母代表什么意思吧

发自我的 iPad

在 2014年5月25日,16:27,Yaoda Liu notifications@github.com 写道:

@fxsjy 请问位置转换概率中 BEMS 是怎么从字、词中分析出来的?我查找了网上大量资料,都没有对此有相关的介绍,一般都是给出词性。


Reply to this email directly or view it on GitHub.

Reply to this email directly or view it on GitHub.

@fxsjy ,请问:你每次训练的时候,是把手头上所有的语料(包括人民日报、MRS,经切词软件处理过的文学材料)全部统计和计算一下吗?这样一次大概需要多长时间呢?

@fxsjy ,我看更新日志发现一开始就把搜狗的2006词库给导入工程中了,就算自己再去下载那个词库那也作用不大吧

有没有jieba分词和其他框架对比的测试?我很想知道结巴分词的排名~~

@fandywang 这个可以参考清华大学中文分词工具介绍部分

commented

您好,有对应的模型训练代码吗?这边想重新利用自己这边的语料训练一个HMM统计分词模型

您好,假设我使用了自定义词典,那么相应的HMM参数(初始状态概率、状态转移概率、观测概率)会不会被重新训练?

@fxsjy 请问能否训练模块posseg下的各个pro_文件?

@fxsjy 请问一下,怎么使用预料来生成自定领域,比如: 新闻 领域 的词典啊?是用HMM 模型吗?

jieba中的hmm模型是否可以用自己的训练语料生成?

@fxsjy 我想请教一下,我对jieba/dict.txt文件进行了调整,另外我也自定义了词典、自定义调整分词、自定义删除,但是每次运行都需要先进行这些操作,否则并不起作用。问题是:我都已经删除了dict.txt中的词语了,为什么还是会分出那个词呢?另外,如何自己训练或修改模型?谢谢!

咨询个问题:我有些词语拆分,可能在默认词库里面存在,我在自定义词库里面对他进行单独的拆分以便于程序能够识别,但是发现效果不理想。举例:默认词库存着“非正常”这词语,实际上我需要程序能够识别出来并拆分为“非”+“正常”这种,我添加了自定义词典不能生效,只能把默认词库的“非正常”删除。因此咨询下默认词库和自定义词库的优先级谁的大?另外对自定义词典的词频理解不是很充分,词频的值是越大越优先识别么?

另外在默认词库里面单个汉字的词频定义都是很大的?这个定义数值取决于什么?

@fxsjy 您好,想请教一下,我想对着一篇论文分词,论文里本身就有关键词一栏,5个关键词用分号隔开的,这五个隔开的词里面如果不做设置,还会被分词吗,能怎么设置,让他看见某个符号分开的词不要去分他吗?

commented

您好,我想问几个问题1、jieba分词的字典dict.txt是经过怎么处理得到的,是Python脚本处理得到的吗?那可是98年人民日报语料库最开始就是新闻,并没有进行分词,还是生语料库,从生语料库经过怎样的处理变成了网上公开的已经标注过的人民日报语料,是人工标注的吗?2、如果是人工标注的话,那现在假设已经得到了被人工标注好了的人民日报语料,里面是已经人工分好词并且词性标注好了的,那得到这个被标注好了的语料库,下一步经过怎样的处理得到jieba中的dict.txt的?如果是python脚本处理的话,是具体怎样处理的呢?

@fxsjy C++ 版本支持paddle 的那个模型吗

@fxsjy 通过对jiebaHMM自定义字典发射字典的处理,以'B'来说,那么P[B|字]代表B状态下某个字的概率,按照统计规律来说,P(B)下所有字的概率只和应该为1,但是我将jieba的hmm中的prob_emit字典读取统计后,发现B下面所有字的概率和是大于1的。具体代码如下:
with open('./prob_emit_测试.py',mode='r',encoding='utf-8') as f:
data=f.readlines()
str=''
for line in data:
line1=line.strip()
str+=line1
dict3=eval(str[2:])
n=0
for key,value in dict3['B'].items():
n+=exp(value)
print('字典里面B所有字的概率合集为',n)

#结果
字典里面B所有字的概率合集为 1.3132772700102078

咨询个问题:我有些词语拆分,可能在默认词库里面存在,我在自定义词库里面对他进行单独的拆分以便于程序能够识别,但是发现效果不理想。举例:默认词库存着“非正常”这词语,实际上我需要程序能够识别出来并拆分为“非”+“正常”这种,我添加了自定义词典不能生效,只能把默认词库的“非正常”删除。因此咨询下默认词库和自定义词库的优先级谁的大?另外对自定义词典的词频理解不是很充分,词频的值是越大越优先识别么?

找到答案了吗 我也有这个疑问呢

@fxsjy 通过对jiebaHMM自定义字典发射字典的处理,以'B'来说,那么P[B|字]代表B状态下某个字的概率,按照统计规律来说,P(B)下所有字的概率只和应该为1,但是我将jieba的hmm中的prob_emit字典读取统计后,发现B下面所有字的概率和是大于1的。具体代码如下:
with open('./prob_emit_测试.py',mode='r',encoding='utf-8') as f:
data=f.readlines()
str=''
for line in data:
line1=line.strip()
str+=line1
dict3=eval(str[2:])
n=0
for key,value in dict3['B'].items():
n+=exp(value)
print('字典里面B所有字的概率合集为',n)

#结果
字典里面B所有字的概率合集为 1.3132772700102078

同问,为什么概率相加不为1。

字典里面B所有字的概率和不为1,请问下是什么原因哈

字典里面B所有字的概率和不为1,请问下是什么原因哈

而且我看都是负数,有什么考虑?

我正在做类似的事情,我有70万数据,先统计单个文字,然后查看文字和其他文字出现的概率,出现在词头和词尾的概率,然后计划生成词典,跑起来速度比较慢,而且吃内存。

commented
commented