分词粒度:粗粒度、细粒度
推荐场景:粗粒度
搜索场景:细粒度——召回
1.最基本的切词方法:
trie树匹配:前向、后向,举例:
2.dag(有向无环图),举例:
3.每种切分方案的概率计算:
贝叶斯公式:
贝叶斯公式推导:
目标:P(S|C) = P(S)
因为:P(S|C) P(C)=P(S,C)
P(C|S) P(S)=P(C,S)
所以:P(S|C) P(C)=P(C|S) P(S)
所以:P(S|C) =P(C|S) P(S)/P(C)
因为:P(C)是一个固定值,P(C|S)=100%()
所以:P(S|C) = P(S)
举例:
如果
C = 本田雅阁
S = 本田 / 雅阁
S = 本 / 田 / 雅阁
那么:
P(C)=本田雅阁(如果有一万个词,那么P(C)=万分之一,固定值)
P(C|S)=P(本田雅阁|本田 / 雅阁)=100%(在有分词推导 出原词的情况下是100%)
按词计算概率:
P(S)=P(W1,W2,W3....)=P(W1)P(W2)P(W3)...
举例:P(S1)=P(南京市,长江,大桥)=P(南京市)*P(长江)*P(大桥) > P(S2)=P(南京,市
长,江大桥),所以选择切分方案S1
近似于log(P(W1))+log(P(W2))+log(P(W3))+....
用log的好处:
1、防止向下溢出
2、加法比乘法速度快
log基本运算法则: log(ab) = log(a) + log(b)
4.每个词的概率计算:
因此:logP(wi ) = log(Freqw ) -logN,这个P(S)的计算公式也叫做基于一元模型的计算公式,它综合考虑了切分出的词
数和词频。
5.N元模型:
如果简化成一个词的出现仅依赖于它前面出现的一个词,那么就称为二元模型
(Bigram)
如果简化成一个词的出现仅依赖于它前面出现的两个词,就称之为三元模型
(Trigram)。
一元模型:P(w1,w2)= P(w1)P(W2)
二元模型:P(w1,w2)= P(w1)P(w2|w1)
三元模型:P(w1,w2,w3)= P(w1,w2)P(w3|w1,w2)
P(S)=P(w1,w2,...,wn)= P(w1)P(w2|w1)P(w3|w1,w2)…P(wn|w1w2…wn-1)
• 这叫做概率的链规则
5.jieba分词
简介:
基于Trie树结构实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成
的有向无环图(DAG)
• 采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合
• 对于未登录词,采用了基于汉字成词能力的HMM模型,使用了Viterbi算法
jieba分词细节:
对于英文的处理方法,举例:
本田are you ready雅阁汽车
会切分成:本田/a/r/e/ y/o/u/ r/e/a/d/y/雅阁/汽车
切分后会传给token将英文全部合并:are you ready
在语料库不完整的情况下,将单独的一个字传给隐马模型处理,再组合
未登录词:未加载到语料库的词
jieba原理:
第一步:对比较脏的信息,去杂质
第二步:做分词(两阶段)
1阶段(trie树):来了一句话,通过词库,把所有切分方案列出来
例如:
但是第一阶段词库未必齐全,例如只有:
广州,本田,雅阁(没有汽车),所以只能切分成广州/本田/雅阁//汽/车
2阶段:通过hhm模型,把切分错的词粘回来,例如:汽/车,还原为汽车
第一阶段的单个字段,传给第二阶段,返回一个词给第一阶段。
第一阶段:
概率计算方法:
P=log(词频/总词数)
第二步:确定最优路径:计算组合和不组合和概率:举例汽车的概率为-8.7,而汽的概率和车的概率单独计算,则-20左右。
一直选择最优的最后概率,最后组合。
至此,完成第一阶段trie树的分词。
第二阶段:隐马尔可夫模型(下一章)
实践
1.下载:
]# git clone https://github.com/fxsjy/jieba.git
如果python不会的,可以看看jieba目录下的python源码,会对python的学习有很大长进。
jieba包下:
tf:在dict.txt中
idf:在idf.txt中
状态(初始,中间,结尾)概率:在jieba/posseg/prob_start.txt中
转移概率:prob_trains.py
发射概率:prob_emit.py
每一个idf和if都提前算好了
实践:如何用mapreduce批量分词
1.打jieba包:jieba.tgz
2.数据:
音乐id和音乐名字,对音乐名字进行分词。
3.map_seg.py进行分词:
import os
import sys
os.system('tar xvzf jieba.tgz > /dev/null')
reload(sys)
sys.setdefaultencoding('utf-8')
sys.path.append("./")
import jieba
import jieba.posseg
import jieba.analyse
for line in sys.stdin:
ss = line.strip().split('\t')
if len(ss) != 2:
continue
music_id = ss[0].strip()
music_name = ss[1].strip()
seg_list = jieba.cut(music_name, cut_all=False)
print '\t'.join([music_id, music_name, ' '.join(seg_list)])
)
run.sh:
执行任务:
结果: