惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LangChain Blog
V
V2EX
爱范儿
爱范儿
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
罗磊的独立博客
小众软件
小众软件
Vercel News
Vercel News
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
J
Java Code Geeks
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog
B
Blog
美团技术团队
量子位

博客园 - Anders Cui

jieba.NET与Lucene.Net的集成 迷人的斐波那契数 趣题一则:交替放置的碟子 用户中心 - 博客园 趣题一则:寻找那扇门 HashSet的实现(下) HashSet的实现(上) 趣题一则:如何快速过桥? 制作自己的wikibook 玩儿一下Word Search Puzzle 整数的展开 离散数学拾趣(三):集合的子集有多少个 找零钱的两种方法 离散数学拾趣(二):逻辑难题 离散数学拾趣(一) 关于命名中的数量和人称 扩展方法浅谈 意外之喜 最近遭遇的两个VS配置
jieba中文分词的.NET版本:jieba.NET
Anders Cui · 2015-09-08 · via 博客园 - Anders Cui

简介

平时经常用Python写些小程序。在做文本分析相关的事情时免不了进行中文分词,于是就遇到了用Python实现的结巴中文分词。jieba使用起来非常简单,同时分词的结果也令人印象深刻,有兴趣的可以到它的在线演示站点体验下(注意第三行文字)。

.NET平台上常见的分词组件是盘古分词,但是已经好久没有更新了。最明显的是内置词典,jieba的词典有50万个词条,而盘古的词典是17万,这样会造成明显不同的分词效果。另外,对于未登录词,jieba“采用了基于汉字成词能力的HMM模型,使用了Viterbi算法”,效果看起来也不错。

基于以上两点,加上对于中文分词的兴趣,就尝试将jieba移植到.NET平台上,已经把代码放在了github上:jieba.NET。在试用jieba.NET之前,先简单介绍下jieba的实现思路。

jieba实现浅析

jieba本身提供的文档较少,但我们可以在《对Python中文分词模块结巴分词算法过程的理解和分析》、《jieba 分词源代码研读(1)》这一系列文章中一窥jieba实现的整体思路。简言之,它的核心模块和分词过程大致是:

  • 前缀词典(Trie):用于存储主词典,也可以动态增删词条,这个词典可以理解为jieba所“知道”的词,或者说已登录词;
  • 有向无环图(DAG):通过前缀词典,可以找出句子所有可能的成词结果;
  • 最大概率路径:通过DAG,可以了解所有的成词结果,每个结果对应于一条路径及其概率。由于不同词条的出现概率不同,不同的结果就对应了不同的概率,我们找出概率最大的那条路径。到这里,我们对于已登录词做出了最合理的划分;
  • HMM模型Viterbi算法:最大概率路径之后,我们可能会遇到一些未登录词(不包含在前缀词典中的词),这时通过HMM和Viterbi尝试进一步的划分,得到最终结果

这个过程与人的分词过程很类似。比如看到这句话:“语言学家参加学术会议”,我们会把它划分为:“语言学家 参加 学术会议”。尽管这个过程是瞬间完成的,但是它确实包含了上述过程的前三步:分词之前,大脑中已有一个“前缀词典”,它包括语言、语言学、语言学家等等各个词条;大脑知道这句话确实存在多种分词的可能;但它最后还是选出了那个最可能的结果,舍弃了诸如“语言学 家 参加 学术 会议”这样的结果。

前面这句话仅包含了已登录词,再来看另一句话:“他来到了网易杭研大厦”。一般人可以迅速做出划分:“他 来到 了 网易 (杭研)? 大厦”,除了“杭研”这两个字,其它的都属于已登录词,容易划分出来。对于“杭研”,我们要想一想它们是两个单字呢,还是一个新词。最后,可能会伴随着这样一个过程:我知道网易是有研发中心或研究院之类的在杭州的,那么“杭研”可能是与此相关的一个缩写,嗯,又知道了一个新词。尽管这个过程与HMM不同,但我们至少了解到,jieba确实是通过某种方式去尝试寻找未登录词。

不过可以想象的是,基于状态转移概率的HMM模型(建议参考文章《中文分词之HMM模型详解》)能够发现的词应该也是比较自然或正常的词,对于新的人名、机构名或网络词(喜大普奔之类的),效果不会很好。

jieba.NET用法

jieba.NET当前版本是0.37.1,与jieba保持一致,可以通过NuGet安装:

PM> Install-Package jieba.NET

安装之后,把Resources目录copy到程序集所在目录即可。下面分别是分词、词性标注和关键词提取的示例。

分词

var segmenter = new JiebaSegmenter();
var segments = segmenter.Cut("我来到北京清华大学", cutAll: true);
Console.WriteLine("【全模式】:{0}", string.Join("/ ", segments));

segments = segmenter.Cut("我来到北京清华大学");  // 默认为精确模式
Console.WriteLine("【精确模式】:{0}", string.Join("/ ", segments));

segments = segmenter.Cut("他来到了网易杭研大厦");  // 默认为精确模式,同时也使用HMM模型
Console.WriteLine("【新词识别】:{0}", string.Join("/ ", segments));

segments = segmenter.CutForSearch("小明硕士毕业于中国科学院计算所,后在日本京都大学深造"); // 搜索引擎模式
Console.WriteLine("【搜索引擎模式】:{0}", string.Join("/ ", segments));

segments = segmenter.Cut("结过婚的和尚未结过婚的");
Console.WriteLine("【歧义消除】:{0}", string.Join("/ ", segments));

运行结果为:

【全模式】:我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学
【精确模式】:我/ 来到/ 北京/ 清华大学
【新词识别】:他/ 来到/ 了/ 网易/ 杭研/ 大厦
【搜索引擎模式】:小明/ 硕士/ 毕业/ 于/ 中国/ 科学/ 学院/ 科学院/ 中国科学院/ 计算/ 计算所/ ,/ 后/ 在/ 日本/ 京都/ 大学/ 日本京都大学/ 深造
【歧义消除】:结过婚/ 的/ 和/ 尚未/ 结过婚/ 的

JiebaSegmenter.Cut方法可通过cutAll来支持两种模式,精确模式和全模式。精确模式是最基础和自然的模式,试图将句子最精确地切开,适合文本分析;而全模式,把句子中所有的可以成词的词语都扫描出来, 速度更快,但是不能解决歧义,因为它不会扫描最大概率路径,也不会通过HMM去发现未登录词。

CutForSearch采用的是搜索引擎模式,在精确模式的基础上对长词再次切分,提高召回率,适合用于搜索引擎分词

词性标注

词性标注采用和ictclas兼容的标记法,关于ictclas和jieba中使用的标记法列表,请参考:词性标记

var posSeg = new PosSegmenter();
var s = "一团硕大无朋的高能离子云,在遥远而神秘的太空中迅疾地飘移";

var tokens = posSeg.Cut(s);
Console.WriteLine(string.Join(" ", tokens.Select(token => string.Format("{0}/{1}", token.Word, token.Flag))));

运行结果

一团/m 硕大无朋/i 的/uj 高能/n 离子/n 云/ns ,/x 在/p 遥远/a 而/c 神秘/a 的/uj 太空/n 中/f 迅疾/z 地/uv 飘移/v

关键词提取

看下面来自维基百科的关于算法的文字:

在数学和计算机科学/算学之中,算法/算则法(Algorithm)为一个计算的具体步骤,常用于计算、数据处理和自动推理。精确而言,算法是一个表示为有限长列表的有效方法。算法应包含清晰定义的指令用于计算函数。

算法中的指令描述的是一个计算,当其运行时能从一个初始状态和初始输入(可能为空)开始,经过一系列有限而清晰定义的状态最终产生输出并停止于一个终态。一个状态到另一个状态的转移不一定是确定的。随机化算法在内的一些算法,包含了一些随机输入。

形式化算法的概念部分源自尝试解决希尔伯特提出的判定问题,并在其后尝试定义有效计算性或者有效方法中成形。这些尝试包括库尔特·哥德尔、雅克·埃尔布朗和斯蒂芬·科尔·克莱尼分别于1930年、1934年和1935年提出的递归函数,阿隆佐·邱奇于1936年提出的λ演算,1936年Emil Leon Post的Formulation 1和艾伦·图灵1937年提出的图灵机。即使在当前,依然常有直觉想法难以定义为形式化算法的情况。

现在来尝试提取其中的关键词。jieba.NET提供了TF-IDF和TextRank两种算法来提取关键词,TF-IDF对应的类是JiebaNet.Analyser.TfidfExtractor,TextRank的是JiebaNet.Analyser.TextRankExtractor

var extractor = new TfidfExtractor();
// 提取前十个仅包含名词和动词的关键词
var keywords = extractor.ExtractTags(text, 10, Constants.NounAndVerbPos); foreach (var keyword in keywords) { Console.WriteLine(keyword); }

运行结果是

算法
定义
计算
尝试
形式化
提出
状态
指令
输入
包含

相应的ExtractTagsWithWeight方法的返回结果中除了包含关键词,还包含了相应的权重值。TextRankExtractor的接口与TfidfExtractor完全一致,不再赘述。

小结

分词、词性标注和关键词提取是jieba的三个主要功能模块,jieba.NET目前尽量在功能和接口上与jieba保持一致,但以后可能会在jieba基础上提供其它扩展功能。jieba.NET的开发刚刚开始,还有很多细节需要完善。非常欢迎大家的试用和反馈,也希望能和大家一起讨论,共同实现更好的中文分词库。

参考:

结巴中文分词

对Python中文分词模块结巴分词算法过程的理解和分析

中文分词之HMM模型详解

结巴分词Java版