一时兴起,想再看看结巴分词。
以前研究时随手找了一个结巴分词来测试使用,发现非常强大,也就玩了一下,然后就没有然后了~。
在github里搜索到了两个结巴分词,共显示两个热度比较高的,链接如下:
以前还没在意,直接使用了一个星星最多的,仔细看了一下
yanyiwu/gojieba 是基于 wangbin/jiebago 分词之上做了一些改进而来的。
今天只说wangbin/jiebago 的分词。
README.md
作者在redme的首行就公布了一些历史:
结巴分词 是由 @fxsjy 使用 Python 编写的中文分词组件,Iiebago 是结巴分词的 Golang 语言实现。
使用
可以看到分词的使用是比较简单的,直接引入相关类使用调几个方法就能输出词汇
package main
import (
"fmt"
"github.com/wangbin/jiebago"
)
var seg jiebago.Segmenter
func init() {
seg.LoadDictionary("dict.txt")
}
func print(ch <-chan string) {
for word := range ch {
fmt.Printf(" %s /", word)
}
fmt.Println()
}
func Example() {
fmt.Print("【全模式】:")
print(seg.CutAll("我来到北京 清华大学 "))
fmt.Print("【精确模式】:")
print(seg.Cut("我来到北京清华大学", false))
fmt.Print("【新词识别】:")
print(seg.Cut("他来到了网易杭研大厦", true))
fmt.Print("【搜索引擎模式】:")
print(seg.CutForSearch("小明硕士毕业于中国科学院 计算所 ,后在日本京都大学深造", true))
}
输出结果:
【全模式】: 我 / 来到 / 北京 / 清华 / 清华大学 / 华大 / 大学 /
【精确模式】: 我 / 来到 / 北京 / 清华大学 /
【新词识别】: 他 / 来到 / 了 / 网易 / 杭研 / 大厦 /
【搜索引擎模式】: 小明 / 硕士 / 毕业 / 于 / 中国 / 科学 / 学院 / 科学院 / 中国科学院 / 计算 / 计算所 / , / 后 / 在 / 日本 / 京都 / 大学 / 日本京都大学 / 深造 /
分词速度
作者更多信息请参考文档。
算法
- 基于前缀词典实现高效的词图扫描,生成句子中汉字所有可能成词情况所构成的有向无环图 (DAG)
- 采用了动态规划查找最大概率路径, 找出基于词频的最大切分组合
- 对于未登录词,采用了基于汉字成词能力的 HMM 模型,使用了 Viterbi 算法
jieba分词词性标记含义
jieba为自然语言语言中常用工具包,jieba具有对分词的词性进行标注的功能,词性类别如下:
创建自定义分词字典
项目中有 userdict.txt,然后写入你的分词,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒,这就是为啥上面要把 词性提出的原因 。
比如
李小福 2 nr
“李小福”是个词语 词频是2(词频越高相应的权重越大)词性是人名
加载用户词典:
...
d := &Dict{freqMap: make(map[string]float64), posMap: make(map[string]string)}
err := LoadDictionary(d, "../userdict.txt")
if err != nil {
t.Fatalf(err.Error())
}
...
添加token:
...
d := &Dict{freqMap: make(map[string]float64), posMap: make(map[string]string)}
LoadDictionary(d, "../userdict.txt")
d.AddToken(Token{"好用", 99, "a"})
...
测试用户词典:
func TestUserDict(t *testing.T) {
seg.LoadUserDictionary("../userdict.txt")
defer seg.LoadDictionary("../dict.txt")
sentence := "李小福是创新办主任也是 云计算 方面的专家; 什么是八一双鹿例如我输入一个带“韩玉赏鉴”的标题,在自定义词库中也增加了此词为N类型"
cutResult := [] Segment {
Segment{"李小福", "nr"},
Segment{"是", "v"},
Segment{"创新办", "i"},
Segment{"主任", "b"},
Segment{"也", "d"},
Segment{"是", "v"},
Segment{"云计算", "x"},
Segment{"方面", "n"},
Segment{"的", "uj"},
Segment{"专家", "n"},
Segment{";", "x"},
Segment{" ", "x"},
Segment{"什么", "r"},
Segment{"是", "v"},
Segment{"八一双鹿", "nz"},
Segment{"例如", "v"},
Segment{"我", "r"},
Segment{"输入", "v"},
Segment{"一个", "m"},
Segment{"带", "v"},
Segment{"“", "x"},
Segment{"韩玉赏鉴", "nz"},
Segment{"”", "x"},
Segment{"的", "uj"},
Segment{"标题", "n"},
Segment{",", "x"},
Segment{"在", "p"},
Segment{"自定义词", "n"},
Segment{"库中", "nrt"},
Segment{"也", "d"},
Segment{"增加", "v"},
Segment{"了", "ul"},
Segment{"此", "r"},
Segment{"词", "n"},
Segment{"为", "p"},
Segment{"N", "eng"},
Segment{"类型", "n"}}
result := chanToArray(seg.Cut(sentence, true))
if len(cutResult) != len(result) {
t.Fatal(result)
}
for i := range result {
if result[i] != cutResult[i] {
t.Fatal(result[i])
}
}
}
总结
感觉就是简单好用,至于有没更深层次的问题,估计需要高频的业务才有结果。