HanLP 自然语言处理使用总结
Posted 小毕超
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HanLP 自然语言处理使用总结相关的知识,希望对你有一定的参考价值。
一、HanLP
HanLP
是一系列模型与算法组成的NLP
工具包,目标是普及自然语言处理在生产环境中的应用。HanLP
具备功能完善、性能高效、架构清晰、语料时新、可自定义的特点。内部算法经过工业界和学术界考验,配套书籍《自然语言处理入门》已经出版。目前,基于深度学习的HanLP 2.x
已正式发布,次世代最先进的NLP
技术,支持包括简繁中英日俄法德在内的104
种语言上的联合任务。
本文参考官方GitHub:https://github.com/hankcs/HanLP/tree/1.x
目前 HanLP 提供了下面功能:
- 中文分词
- 词性标注
- 命名实体识别
- 关键词提取
- 自动摘要
- 短语提取
- 拼音转换
- 多音字、声母、韵母、声调
- 简繁转换
- 简繁分歧词(简体、繁体、臺灣正體、香港繁體)
- 文本推荐
- 语义推荐、拼音推荐、字词推荐
- 依存句法分析
- 文本分类
- 文本聚类
- KMeans、Repeated Bisection、自动推断聚类数目k
- word2vec
- 词向量训练、加载、词语相似度计算、语义运算、查询、KMeans聚类
- 文档语义相似度计算
- 语料库工具
- 部分默认模型训练自小型语料库,鼓励用户自行训练。所有模块提供训练接口,语料可参考98年人民日报语料库。
在提供丰富功能的同时,HanLP
内部模块坚持低耦合、模型坚持惰性加载、服务坚持静态提供、词典坚持明文发布,使用非常方便。默认模型训练自全世界最大规模的中文语料库,同时自带一些语料处理工具,帮助用户训练自己的模型。
二、Java Maven项目环境准备
首先新建一个普通 Maven
项目,在 pom
中增加依赖:
<dependency>
<groupId>com.hankcs</groupId>
<artifactId>hanlp</artifactId>
<version>portable-1.8.3</version>
</dependency>
此时即可使用基本功能(除由字构词、依存句法分析外的全部功能)。如果需要使用全部功能还需下载词典和模型,下载地址:
将下载后的data
目录,拷贝至项目的 resources
目录下:
其中数据分为词典和模型,其中词典是词法分析必需的,模型是句法分析必需的,用户可以自行增删替换,如果不需要句法分析等功能的话,随时可以删除model
文件夹。
下面还需要进行 HanLP
的配置,可以下载官方的配置模板:
下载解压后,jar
包上面已经通过 Maven
引入,只需将hanlp.properties
文件拷贝至 resources
目录下,并修改下面配置:
root=src/main/resources
编写测试程序,测试环境:
public class Test1
public static void main(String[] args)
String text = "你好,欢迎使用HanLP汉语处理包!";
//标准分词
System.out.println(HanLP.segment(text));
//nlp 分词
System.out.println(NLPTokenizer.segment(text));
成功拿到结果便环境正常:
三、HanLP 使用
1. 基础分词
础分词,基础分词只进行基本NGram
分词,不识别命名实体,不使用用户词典,分词后会带有词性,词性的标注集放在了文章最后:
public class DemoBasicTokenizer
public static void main(String[] args)
String text = "程序员(英文Programmer)是从事程序开发、维护的专业人员。" +
"一般将程序员分为程序设计人员和程序编码人员," +
"但两者的界限并不非常清楚,特别是在中国。" +
"软件从业人员分为初级程序员、高级程序员、系统" +
"分析员和项目经理四大类。";
System.out.println(BasicTokenizer.segment(text));
// 测试分词速度,让大家对HanLP的性能有一个直观的认识
long start = System.currentTimeMillis();
int pressure = 100000;
for (int i = 0; i < pressure; ++i)
BasicTokenizer.segment(text);
double costTime = (System.currentTimeMillis() - start) / (double) 1000;
System.out.printf("BasicTokenizer分词速度:%.2f字每秒\\n", text.length() * pressure / costTime);
2. 极速分词
基于DoubleArrayTrie
实现的词典正向最长分词,适用于“高吞吐量”“精度一般”的场合
public class DemoHighSpeedSegment
public static void main(String[] args)
String text = "江西鄱阳湖干枯,中国最大淡水湖变成大草原";
HanLP.Config.ShowTermNature = false;
System.out.println(SpeedTokenizer.segment(text));
long start = System.currentTimeMillis();
int pressure = 1000000;
for (int i = 0; i < pressure; ++i)
SpeedTokenizer.segment(text);
double costTime = (System.currentTimeMillis() - start) / (double)1000;
System.out.printf("SpeedTokenizer分词速度:%.2f字每秒\\n", text.length() * pressure / costTime);
3. 标准分词
public class DemoSegment
public static void main(String[] args)
String[] testCase = new String[]
"商品和服务",
"当下雨天地面积水分外严重",
"结婚的和尚未结婚的确实在干扰分词啊",
"买水果然后来世博园最后去世博会",
"中国的首都是北京",
"欢迎新老师生前来就餐",
"工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作",
"随着页游兴起到现在的页游繁盛,依赖于存档进行逻辑判断的设计减少了,但这块也不能完全忽略掉。",
;
for (String sentence : testCase)
//对StandardTokenizer.segment的包装
List<Term> termList = HanLP.segment(sentence);
System.out.println(termList);
4. CRF词法分词
自1.6.6版起模型格式不兼容旧版:CRF模型为对数线性模型,通过复用结构化感知机的维特比解码算法,效率提高10倍。
public class DemoCRFLexicalAnalyzer
public static void main(String[] args) throws IOException
CRFLexicalAnalyzer analyzer = new CRFLexicalAnalyzer();
String[] tests = new String[]
"商品和服务",
"上海华安工业(集团)公司董事长谭旭光和秘书胡花蕊来到美国纽约现代艺术博物馆参观",
"微软公司於1975年由比爾·蓋茲和保羅·艾倫創立,18年啟動以智慧雲端、前端為導向的大改組。" // 支持繁体中文
;
for (String sentence : tests)
System.out.println(analyzer.seg(sentence));
5. NLP分词
更精准的中文分词、词性标注与命名实体识别。语料库规模决定实际效果,面向生产环境的语料库应当在千万字量级。
词性标注可以使用 Sentence#translateLabels()
转为中文显示:
public class DemoNLPSegment extends TestUtility
public static void main(String[] args)
NLPTokenizer.ANALYZER.enableCustomDictionary(false); // 中文分词≠词典,不用词典照样分词。
System.out.println(NLPTokenizer.segment("我新造一个词叫幻想乡你能识别并正确标注词性吗?")); // “正确”是副形词。
// 注意观察下面两个“希望”的词性、两个“晚霞”的词性
System.out.println(NLPTokenizer.analyze("我的希望是希望张晚霞的背影被晚霞映红").translateLabels());
System.out.println(NLPTokenizer.analyze("支援臺灣正體香港繁體:微软公司於1975年由比爾·蓋茲和保羅·艾倫創立。"));
6. 索引分词
public class DemoIndexSegment
public static void main(String[] args)
List<Term> termList = IndexTokenizer.segment("主副食品");
for (Term term : termList)
System.out.println(term + " [" + term.offset + ":" + (term.offset + term.word.length()) + "]");
System.out.println("\\n最细颗粒度切分:");
IndexTokenizer.SEGMENT.enableIndexMode(1);
termList = IndexTokenizer.segment("主副食品");
for (Term term : termList)
System.out.println(term + " [" + term.offset + ":" + (term.offset + term.word.length()) + "]");
7. 多线程并行分词
由于HanLP
的任何分词器都是线程安全的,所以用户只需调用一个配置接口就可以启用任何分词器的并行化
public class DemoMultithreadingSegment
public static void main(String[] args) throws IOException
Segment segment = new CRFLexicalAnalyzer(HanLP.Config.CRFCWSModelPath).enableCustomDictionary(false); // CRF分词器效果好,速度慢,并行化之后可以提高一些速度
String text = "程序员(英文Programmer)是从事程序开发、维护的专业人员。" +
"一般将程序员分为程序设计人员和程序编码人员," +
"但两者的界限并不非常清楚,特别是在中国。" +
"软件从业人员分为初级程序员、高级程序员、系统" +
"分析员和项目经理四大类。";
HanLP.Config.ShowTermNature = false;
System.out.println(segment.seg(text));
int pressure = 10000;
StringBuilder sbBigText = new StringBuilder(text.length() * pressure);
for (int i = 0; i < pressure; i++)
sbBigText.append(text);
text = sbBigText.toString();
System.gc();
long start;
double costTime;
// 测个速度
segment.enableMultithreading(false);
start = System.currentTimeMillis();
segment.seg(text);
costTime = (System.currentTimeMillis() - start) / (double) 1000;
System.out.printf("单线程分词速度:%.2f字每秒\\n", text.length() / costTime);
System.gc();
segment.enableMultithreading(true); // 或者 segment.enableMultithreading(4);
start = System.currentTimeMillis();
segment.seg(text);
costTime = (System.currentTimeMillis() - start) / (double) 1000;
System.out.printf("多线程分词速度:%.2f字每秒\\n", text.length() / costTime);
System.gc();
// Note:
// 内部的并行化机制可以对1万字以上的大文本开启多线程分词
// 另一方面,HanLP中的任何Segment本身都是线程安全的。
// 你可以开10个线程用同一个CRFSegment对象切分任意文本,不需要任何线程同步的措施,每个线程都可以得到正确的结果。
8. AhoCorasickDoubleArrayTrie 分词
AhoCorasickDoubleArrayTrieSegment
要求用户必须提供自己的词典路径
准备词典:
微观经济学
继续教育
循环经济
public class DemoUseAhoCorasickDoubleArrayTrieSegment
public static void main(String[] args) throws IOException
AhoCorasickDoubleArrayTrieSegment segment = new AhoCorasickDoubleArrayTrieSegment("data/dictionary/custom/my.txt");
System.out.println(segment.seg("微观经济学继续教育循环经济"));
9. 繁体中文分词
public class DemoTraditionalChineseSegment
public static void main(String[] args)
List<Term> termList = TraditionalChineseTokenizer.segment("大衛貝克漢不僅僅是名著名球員,球場以外,其妻為前" +
"辣妹合唱團成員維多利亞·碧咸,亦由於他擁有" +
"突出外表、百變髮型及正面的形象,以至自己" +
"品牌的男士香水等商品,及長期擔任運動品牌" +
"Adidas的代言人,因此對大眾傳播媒介和時尚界" +
"等方面都具很大的影響力,在足球圈外所獲得的" +
"認受程度可謂前所未見。");
System.out.println(termList);
termList = TraditionalChineseTokenizer.segment("(中央社記者黃巧雯台北20日電)外需不振,影響接單動能,經濟部今天公布7月外銷訂單金額362.9億美元,年減5%," +
"連續4個月衰退,減幅較6月縮小。1040820\\n");
System.out.println(termList);
termList = TraditionalChineseTokenizer.segment("中央社记者黄巧雯台北20日电");
System.out.println(termList);
10. N最短路径分词
该分词器比最短路分词器慢,但是效果稍微好一些,对命名实体识别能力更强
public class DemoNShortSegment
public static void main(String[] args)
Segment nShortSegment = new NShortSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
Segment shortestSegment = new ViterbiSegment().enableCustomDictionary(false).enablePlaceRecognize(true).enableOrganizationRecognize(true);
String[] testCase = new String[]
"一般将程序员分为程序设计人员和程序编码人员",
"软件从业人员分为初级程序员、高级程序员、系统分析员和项目经理四大类。",
"程序员(英文Programmer)是从事程序开发、维护的专业人员。",
;
for (String sentence : testCase)
System.out.println("N-最短分词:" + nShortSegment.seg(sentence) + "\\n最短路分词:" + shortestSegment.seg(sentence));
11. 自定义词性,以及往词典中插入自定义词性的词语
public class DemoCustomNature
public static void main(String[] args)
// 对于系统中已有的词性,可以直接获取
Nature pcNature = Nature.fromString("n");
System.out.println(pcNature);
// 此时系统中没有"电脑品牌"这个词性
pcNature = Nature.fromString("电脑品牌");
System.out.println(以上是关于HanLP 自然语言处理使用总结的主要内容,如果未能解决你的问题,请参考以下文章