大家好,又见面了,我是你们的朋友全栈君。
结巴分词
结巴分词是有国内程序员(https://github.com/fxsjy/jieba)做的一个分词工具,刚开始是Python版本的,后来由anderscui(https://github.com/anderscui/jieba.NET )移植到.Net上面。
结巴分词的分词过程大致为:
·前缀词典(Trie):用于存储主词典,也可以动态增删词条,这个词典可以理解为jieba所“知道”的词,或者说已登录词;
·有向无环图(DAG):通过前缀词典,可以找出句子所有可能的成词结果;
·最大概率路径:通过DAG,可以了解所有的成词结果,每个结果对应于一条路径及其概率。由于不同词条的出现概率不同,不同的结果就对应了不同的概率,我们找出概率最大的那条路径。到这里,我们对于已登录词做出了最合理的划分;
·HMM模型和Viterbi算法:最大概率路径之后,我们可能会遇到一些未登录词(不包含在前缀词典中的词),这时通过HMM和Viterbi尝试进一步的划分,得到最终结果
刚开始结巴分词只有分词功能,后来加入了词性标注、关键词提取等功能,加上其开源的属性,还是很好用的。
安装方法
通过NuGet包管理器安装jieba.NET
在当前项目安装了结巴分词之后,可以在当前项目的packages\jieba.NET\文件夹下看到一个Resource文件夹,里面是结巴分词所需要的各种数据文件,需要对数据文件的位置进行配置才能使用。有几种方法:
方法一、对于VS项目来说,直接将Resource文件夹拷贝到项目的bin\Debug\目录下。
方法二、修改VS的配置文件app.config,加入如下配置项。
<appSettings>
<add key=”JiebaConfigFileDir” value=fileDir />
</appSettings>
其中的fileDir就是Resource文件夹的内容所在的目录
Jieba.NET使用
分词
结巴提供了三种分词的方法:
精确模式:试图将句子最精确地切开,适合文本分析;
全模式:把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义问题;
搜索引擎模式:在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。
对于未登录词,采用了基于汉字成词能力的HMM模型,使用了Viterbi算法。
下面请看详细用法:
1. 精确模式
<span style="color:#333333"><span style="background-color:#f5f5f5">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiebaNet.Analyser;
using JiebaNet.Segmenter;
namespace JiebaTest
{
class Program
{
static void Main(string[] args)
{
string text = "当人类得知宇宙的黑暗森林状态后,这个在篝火旁大喊的孩子立刻 浇灭了火,在黑暗中瑟瑟发抖,连一颗火星都害怕了。在最初的几天里,甚至民用移动通信都被禁止,全球大部分通信基站 都被强令关闭。";
var segmenter = new JiebaSegmenter();
//使用精确模式,函数参数:待分词文本,关闭全模式,不使用hmm模型
var result = segmenter.Cut(text,cutAll: false, hmm: false);
Console.WriteLine("{0}", string.Join("/", result));
Console.ReadKey();
}
}
}</span></span>
运行结果:
2. 全模式
与精确模式不同的只有如下一句:
<span style="color:#333333"><span style="background-color:#f5f5f5">var result1 = segmenter.Cut(text, cutAll:true, hmm: false);</span></span>
可以看到会有重复分词的现象,这是因为结巴分词把歧义词项一并列出来的缘故。
3. 搜索模式
<span style="color:#333333"><span style="background-color:#f5f5f5"> var result2 = segmenter.CutForSearch(text,hmm:true);
Console.WriteLine("{0}", string.Join("/", result2));</span></span>
CutForSearch()只有两个参数,意义也和精确模式一样,程序运行结果:
自定义分词
很多时候我们需要针对自己的场景进行分词,会有一些领域内的专有词汇。这时候我们需要让分词器能识别特定的词或者不识别特定的词。有两种方法:
1. 对于少量的词汇,我们可以通过AddWord()函数添加新词和调整词频,通过DeleteWord()函数删除词典中的某一词使分词器不再将其作为一个词;若AddWord()的参数freq不是正整数,则使用自动计算出的词频,计算出的词频可保证该词被分出来。
2. 通过LoadUserDict(“usr_dict_path”)函数添加自定义的词典。开发者可以指定自定义的词典,以便包含jieba词库里没有的词。虽然jieba有新词识别能力,但是自行添加新词可以保证更高的正确率。词典格式与主词典格式相同,即一行包含:词、词频(可省略)、词性(可省略),用空格隔开。词频省略时,分词器将使用自动计算出的词频保证该词被分出。
下面请看详细介绍:
1.AddWord()和DeleteWord()的使用
程序运行结果:
<span style="color:#333333"><span style="background-color:#f5f5f5">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JiebaNet.Analyser;
using JiebaNet.Segmenter;
namespace JiebaTest
{
class Program
{
static void Main(string[] args)
{
var segmenter = new JiebaSegmenter();
string hello = "大家好,这个人叫陈建驱";
var result_hello = segmenter.Cut(hello,hmm:false);
Console.WriteLine("{0}", string.Join("/", result_hello));
segmenter.AddWord("陈建驱",freq:0,tag:null);
var result_hello1 = segmenter.Cut(hello, hmm: false);
Console.WriteLine("{0}", string.Join("/", result_hello1));
segmenter.DeleteWord("陈建驱"); //使用JiebaSegmenter.DeleteWord(word)可移除一个词,使其不能被分出来
var result_hello2 = segmenter.Cut(hello, hmm: false);
Console.WriteLine("{0}", string.Join("/", result_hello2));
Console.ReadKey();
}
}
}</span></span>
2.加载自定义词典
首先加载这个词典,我把它放到了运行目录下:
然后对比加载词典前后的区别,代码如下:
<span style="color:#333333"><span style="background-color:#f5f5f5">segmenter.LoadUserDict("usr_dict_file_path");
var result_hello1 = segmenter.Cut(hello, hmm: false);
Console.WriteLine("{0}", string.Join("/", result_hello1));</span></span>
运行结果:
待续。。。
关键词提取
Jieba有两种关键词提取的算法,一种是基于TF-IDF算法的关键词提取,另一种是基于TextRank算法的关键词提取。后者在语料库小时效果较差。
TF-IDF关键词抽取基于逆向文件频率(IDF),组件内置一个IDF语料库,可以配置为其它自定义的语料库。关键词抽取会过滤停用词(Stop Words),组件内置一个停用词语料库,这个语料库合并了NLTK的英文停用词和哈工大的中文停用词。
1. 基于TF-IDF的关键词提取
通过TfidfExtractor类的ExtractTags()方法调用该算法,刚方法有四个参数,各个参数的意义如下:
text:待提取的文本
count:选取权值最高的count个词返回
allowPos:对哪些词进行选取,null为默认值,表示不过滤特定的词
代码实现:
<span style="color:#333333"><span style="background-color:#f5f5f5">using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using JiebaNet.Analyser;using JiebaNet.Segmenter; namespace JiebaTest{ class Program { static void Main(string[] args) { string text1 = "在塔的二层,被剑钉在墙上的女魔法师死了,她可能是人类历史上唯 一真正的魔法师。而在这之前约十小时,短暂的魔法时代也结束了。魔 法时代开始于公元 1453 年 5 月 3 日 16 时,那时高维碎块首次接触地球; 结束于 1453 年 5 月 28 日 21 时,这时碎块完全离开地球;历时二十五天 五小时。之后,这个世界又回到了正常的轨道上。29 日傍晚,君士坦丁堡陷落了。在一天的惨烈血战接近尾声时,君士坦丁十一世面对着蜂拥而来的 奥斯曼军队,高喊一声:“滩道就没有一个基督徒来砍下我的头吗?!”然后 皇帝掀下紫袍,拔剑冲人敌阵,他那银色的盔甲像扔进暗红色镪水的一小 片锡箔,转瞬间无影无踪。。。。。。君士坦丁堡陷落的历史意义许久之后才显现出来,事情发生时人们 首先想到的,就是罗马帝国终于完全消失了。拜占庭是古罗马拖在身后 的长达千年的车辙,虽也有过辉煌,但还是终于像烈日下的水渍一样蒸发 了。当年,古罗马人在宏伟华丽的浴宫中吹着口哨,认为帝国就像身下的 浴池一样,建在整块花岗岩上,将永世延续。现在人们知道,没有不散的宴席,一切都有个尽头。"; var tf_idf = new TfidfExtractor(); var tem = tf_idf.ExtractTags(text1, count: 10, allowPos: null); Console.WriteLine("{0}", string.Join("/", tem)); Console.WriteLine("\n"); //带权重的关键词提取 var temW = tf_idf.ExtractTagsWithWeight(text1, count: 10, allowPos: null); foreach(var t in temW) Console.WriteLine("{0} {1}",t.Word,t.Weight); Console.WriteLine("\n"); Console.ReadKey(); } }}</span></span>
运行结果:
2. 基于TextRank的关键词提取
该算法通过TextRankExtractor类的ExtractTags()类调用,方法参数和上面的一样。下面的代码中对提取的范围进行了限制,只分析动词和名词。
代码实现:
<span style="color:#333333"><span style="background-color:#f5f5f5">List<string> strlist = new List<string>();strlist.Add("n");strlist.Add("v");IEnumerable<string> allow=strlist;//基于TextRank的关键词提取,接口和TF-IDF一样var textRankExtractor = new TextRankExtractor();//textRankExtractor.Span = 5;//调整固定窗口的大小var tem1 = textRankExtractor.ExtractTags(text1,count:10,allowPos:allow);Console.WriteLine("{0}", string.Join("/", tem1));Console.WriteLine("\n");var tem2 = textRankExtractor.ExtractTagsWithWeight(text1, count: 10, allowPos: null);foreach (var t in tem2) Console.WriteLine("{0} {1}", t.Word, t.Weight);Console.WriteLine("\n");</span></span>
运行结果:
词性标注
通过jieba.posseg.POSTokenizer(tokenizer=None) 可以自定义分词器,tokenizer 参数可指定内部使用的 jieba.Tokenizer 分词器。jieba.posseg.dt 为默认词性标注分词器。标注句子分词后每个词的词性,采用和 ictclas 兼容的标记法。
代码如下:
<span style="color:#333333"><span style="background-color:#f5f5f5">var posSegmenter = new JiebaNet.Segmenter.PosSeg.PosSegmenter();
var tokens = posSegmenter.Cut(text);
Console.WriteLine(string.Join(" ", tokens.Select(token => string.Format("{0}/{1}", token.Word, token.Flag))));</span></span>
运行结果:
词性符号采用《计算所汉语词性标记集》,详情可查看附录。
获取单词位置
代码实现:
<span style="color:#333333"><span style="background-color:#f5f5f5">var tk = segmenter.Tokenize(text);
//var tk1 = segmenter.Tokenize(text,TokenizerMode.Search);//搜索模式
foreach(var t in tk)
Console.WriteLine("word{0,-12} start:{1,-3} end:{2,-3}", t.Word, t.StartIndex, t.EndIndex);</span></span>
运行结果:
参考文献
[1]CSDN博客:山鹰的天空. jieba.NET是jieba中文分词的.NET版本(C#实现)。.
https://blog.csdn.net/lansetiankong12/article/details/53485816. 2016-12-06
[2]博客园:Ander Cui. jieba中文分词的.NET版本:jieba.NET.
https://www.cnblogs.com/anderslly/p/jiebanet.html .2015-09-08
附录
计算所汉语词性标记集
Version 3.0
制订人:刘群 张华平 张浩
0. 说明
计算所汉语词性标记集(共计99个,22个一类,66个二类,11个三类)主要用于中国科学院计算技术研究所研制的汉语词法分析器、句法分析器和汉英机器翻译系统。
1. 名词 (1个一类,7个二类,5个三类)
名词分为以下子类:
n 名词
nr 人名
nr1 汉语姓氏
nr2 汉语名字
nrj 日语人名
nrf 音译人名
ns 地名
nsf 音译地名
nt 机构团体名
nz 其它专名
nl 名词性惯用语
ng 名词性语素
2. 时间词(1个一类,1个二类)
t 时间词
tg 时间词性语素
3. 处所词(1个一类)
s 处所词
4. 方位词(1个一类)
f 方位词
5. 动词(1个一类,9个二类)
v 动词
vd 副动词
vn 名动词
vshi 动词“是”
vyou 动词“有”
vf 趋向动词
vx 形式动词
vi 不及物动词(内动词)
vl 动词性惯用语
vg 动词性语素
6. 形容词(1个一类,4个二类)
a 形容词
ad 副形词
an 名形词
ag 形容词性语素
al 形容词性惯用语
7. 区别词(1个一类,2个二类)
b 区别词
bl 区别词性惯用语
8. 状态词(1个一类)
z 状态词
9. 代词(1个一类,4个二类,6个三类)
r 代词
rr 人称代词
rz 指示代词
rzt 时间指示代词
rzs 处所指示代词
rzv 谓词性指示代词
ry 疑问代词
ryt 时间疑问代词
rys 处所疑问代词
ryv 谓词性疑问代词
rg 代词性语素
10. 数词(1个一类,1个二类)
m 数词
mq 数量词
11. 量词(1个一类,2个二类)
q 量词
qv 动量词
qt 时量词
12. 副词(1个一类)
d 副词
13. 介词(1个一类,2个二类)
p 介词
pba 介词“把”
pbei 介词“被”
14. 连词(1个一类,1个二类)
c 连词
cc 并列连词
15. 助词(1个一类,15个二类)
u 助词
uzhe 着
ule 了 喽
uguo 过
ude1 的 底
ude2 地
ude3 得
usuo 所
udeng 等 等等 云云
uyy 一样 一般 似的 般
udh 的话
uls 来讲 来说 而言 说来
uzhi 之
ulian 连 (“连小学生都会”)
16. 叹词(1个一类)
e 叹词
17. 语气词(1个一类)
y 语气词(delete yg)
18. 拟声词(1个一类)
o 拟声词
19. 前缀(1个一类)
h 前缀
20. 后缀(1个一类)
k 后缀
21. 字符串(1个一类,2个二类)
x 字符串
xe Email字符串
xs 微博会话分隔符
xm 表情符合
xu 网址URL
22. 标点符号(1个一类,16个二类)
w 标点符号
wkz 左括号,全角:( 〔 [ { 《 【 〖 〈 半角:( [ { <
wky 右括号,全角:) 〕 ] } 》 】 〗 〉 半角: ) ] { >
wyz 左引号,全角:“ ‘ 『
wyy 右引号,全角:” ’ 』
wj 句号,全角:。
ww 问号,全角:? 半角:?
wt 叹号,全角:! 半角:!
wd 逗号,全角:, 半角:,
wf 分号,全角:; 半角: ;
wn 顿号,全角:、
wm 冒号,全角:: 半角: :
ws 省略号,全角:…… …
wp 破折号,全角:―― -- ――- 半角:— —-
wb 百分号千分号,全角:% ‰ 半角:%
wh 单位符号,全角:¥ $ £ ° ℃ 半角:$
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/149464.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...