分詞工具比較及使用(ansj、hanlp徙硅、jieba)

一榜聂、分詞工具

ansjhanlp嗓蘑、jieba

二须肆、優(yōu)缺點

1. ansj

優(yōu)點:

  • 提供多種分詞方式
  • 可直接根據(jù)內(nèi)部詞庫分出人名匿乃、機構(gòu)等信息
  • 可構(gòu)造多個詞庫,在分詞時可動態(tài)選擇所要使用的詞庫

缺點:

  • 自定義詞典時豌汇,系統(tǒng)詞典還是被優(yōu)先使用幢炸,導(dǎo)致詞性不是自定義詞典中的詞性
  • 多單詞英文姓名無法分出

適用場景

  • 若不使用自定義分詞,可直接使用ansj

2. hanlp

優(yōu)點:

  • 自定義分詞拒贱、詞性方便
  • 可分出多單詞的英文名稱(詞典數(shù)據(jù)可帶空格)
  • 可動態(tài)增刪詞庫,
  • 動態(tài)添加詞典前五千萬速度很快宛徊,5m左右

缺點:

  • 動態(tài)添加詞典前五千萬快的很,越往后越慢
  • 詞典文件添加自定義詞典速度略慢逻澳,添加100w需要2m30s

適用場景:

  • 詞典數(shù)量少于五千萬闸天,詞典數(shù)據(jù)若包含空格,用hanlp比較合適

3. jieba

優(yōu)點:

  • 自定義分詞斜做、詞性方便
  • 詞典文件添加自定義詞典比hanlp快苞氮,詞典文件添加100w需要1m,八千萬 2h多

缺點:

  • 自定義詞典時陨享,帶空格的詞不支持

適用場景:

  • 詞典數(shù)量大于五千萬
  • 詞典數(shù)據(jù)不能包含空格葱淳,否則分不出

ansj的使用

1. maven引入ansj包

<ansj.version>5.0.4</ansj.version>
<tree_split.version>1.5</tree_split.version>
<nlp-lang.version>1.7.7</nlp-lang.version>

<!-- ansj_seg -->
<dependency>
  <groupId>org.ansj</groupId>
  <artifactId>ansj_seg</artifactId>
  <version>${ansj.version}</version>
</dependency>
<!-- tree_split -->
<dependency>
  <groupId>org.ansj</groupId>
  <artifactId>tree_split</artifactId>
  <version>${tree_split.version}</version>
</dependency>
<!-- nlp-lang -->
<dependency>
  <groupId>org.nlpcn</groupId>
  <artifactId>nlp-lang</artifactId>
  <version>${nlp-lang.version}</version>
</dependency>

2. 在項目根目錄下創(chuàng)建library文件夾,文件夾下包括以下幾個詞典文件(自行添加)

ambiguity.dic
default.dic
userLibrary.dic

3. 使用

package com.zhen.segment;

import java.io.InputStream;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.ansj.domain.Result;
import org.ansj.domain.Term;
import org.ansj.library.UserDefineLibrary;
import org.ansj.splitWord.analysis.BaseAnalysis;
import org.ansj.splitWord.analysis.NlpAnalysis;
import org.ansj.splitWord.analysis.ToAnalysis;
import org.nlpcn.commons.lang.tire.domain.Forest;
import org.nlpcn.commons.lang.tire.domain.Value;
import org.nlpcn.commons.lang.tire.library.Library;

/**
 * @author FengZhen
 * @date Jan 30, 2019
 * ansj分詞
 */
public class SegmentTest {

    public static void main(String[] args) {
//        dynamicWord();
//        localDic();
//        moreUserDic();
    }
    
    /**
     * 多用戶詞典(新增抛姑、刪除)
     */
    public static void moreUserDic() {
        // 多用戶詞典
        String str = "神探夏洛克這部電影作者.是一個dota迷";
        System.out.println(ToAnalysis.parse(str));
        // 兩個詞匯 神探夏洛克 douta迷
        Forest dic1 = new Forest();
        Library.insertWord(dic1, new Value("神探夏洛克", "define", "1000"));
        Forest dic2 = new Forest();
        Library.insertWord(dic2, new Value("dota迷", "define", "1000"));
        System.out.println(ToAnalysis.parse(str, dic1, dic2));
        
        System.out.println("-------刪除dic1中的詞");
        Library.removeWord(dic1, "神探夏洛克");
        System.out.println(ToAnalysis.parse(str, dic1, dic2));
    }
    
    /**
     * 動態(tài)增刪詞庫
     */
    public static void dynamicWord(){
        // 增加新詞,中間按照'\t'隔開
        UserDefineLibrary.insertWord("ansj中文分詞", "userDefine", 1000);
        Result result =  ToAnalysis.parse("我覺得Ansj中文分詞是一個不錯的系統(tǒng)!我是王婆!");
        System.out.println("增加新詞例子:" + result);
        // 刪除詞語,只能刪除.用戶自定義的詞典.
        UserDefineLibrary.removeWord("ansj中文分詞");
        result = ToAnalysis.parse("我覺得ansj中文分詞是一個不錯的系統(tǒng)!我是王婆!");
        System.out.println("刪除用戶自定義詞典例子:" + result);

        //將用戶自定義詞典清空
        UserDefineLibrary.clear();
    }

    /**
     * 加載詞典文件
     */
    public static void localDic(){
        try {
            //讀的是根目錄下的
            Forest rootForest = Library.makeForest("library/userLibrary.dic");
            System.out.println(rootForest.toMap());
            //加載字典文件,取的是resource下的
            InputStream inputStream = SegmentTest.class.getResourceAsStream("/library/userLibrary.dic");
            Forest resoutceForest=Library.makeForest(inputStream);
            String str = "我覺得ansj中文分詞是一個不錯的系統(tǒng)!我是王婆!";
            Result result=ToAnalysis.parse(str, resoutceForest);//傳入forest
            List<Term> termList=result.getTerms();
            for(Term term:termList){
                System.out.println(term.getName()+":"+term.getNatureStr());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 基本分詞
     * 基本就是保證了最基本的分詞.詞語顆粒度最非常小的..所涉及到的詞大約是10萬左右.
     * 基本分詞速度非常快.在macAir上.能到每秒300w字每秒.同時準(zhǔn)確率也很高.但是對于新詞他的功能十分有限
     * @param content
     */
    public static void baseAnay(String content) {
        Result result = BaseAnalysis.parse(delHTMLTag(content).replace("\n","").replace(" ", "").replace("\t",""));
        System.out.println("result:" + result);
    }

    /**
     * 精準(zhǔn)分詞
     * 它在易用性,穩(wěn)定性.準(zhǔn)確性.以及分詞效率上.都取得了一個不錯的平衡.
     * @param content
     */
    public static void toAnay(String content){
        Result result = ToAnalysis.parse(content);
        System.out.println("result:" + result);
    }

    /**
     * nlp分詞(單條新聞處理7秒)
     * 可以識別出未登錄詞.但是它也有它的缺點.速度比較慢.穩(wěn)定性差.ps:我這里說的慢僅僅是和自己的其他方式比較.應(yīng)該是40w字每秒的速度吧.
     * 個人覺得nlp的適用方式.1.語法實體名抽取.未登錄詞整理.只要是對文本進行發(fā)現(xiàn)分析等工作
     * 會把企業(yè)分開
     * @param content
     */
    public static void nlpAnay(String content){
        Result result = NlpAnalysis.parse(delHTMLTag(content).replace("\n","").replace(" ", "").replace("\t",""));
        System.out.println("result:" + result);
        List<Term> terms = result.getTerms();
        for (Term term : terms) {
            String name = term.getName();
            String nature = term.getNatureStr();
            if (nature.equals("nt") || nature.equals("nr")) {
                System.out.println("------------------");
                System.out.println("getName:" + term.getName());
                System.out.println("getNatureStr:" + term.getNatureStr());
            }
        }
    }

    /**
     * 篩除HTML標(biāo)簽
     * @param htmlStr
     * @return
     */
    public static String delHTMLTag(String htmlStr){
        String regEx_script="<script[^>]*?>[\\s\\S]*?<\\/script>"; //定義script的正則表達式
        String regEx_style="<style[^>]*?>[\\s\\S]*?<\\/style>"; //定義style的正則表達式
        String regEx_html="<[^>]+>"; //定義HTML標(biāo)簽的正則表達式

        Pattern p_script=Pattern.compile(regEx_script,Pattern.CASE_INSENSITIVE);
        Matcher m_script=p_script.matcher(htmlStr);
        htmlStr=m_script.replaceAll(""); //過濾script標(biāo)簽

        Pattern p_style=Pattern.compile(regEx_style,Pattern.CASE_INSENSITIVE);
        Matcher m_style=p_style.matcher(htmlStr);
        htmlStr=m_style.replaceAll(""); //過濾style標(biāo)簽

        Pattern p_html=Pattern.compile(regEx_html,Pattern.CASE_INSENSITIVE);
        Matcher m_html=p_html.matcher(htmlStr);
        htmlStr=m_html.replaceAll(""); //過濾html標(biāo)簽

        return htmlStr.trim(); //返回文本字符串
    }
    
}

hanlp的使用

1. maven添加依賴

<dependency>
    <groupId>com.hankcs</groupId>
    <artifactId>hanlp</artifactId>
    <version>portable-1.7.1</version>
</dependency>

2. 動態(tài)添加詞

/**
     * 新增詞
     */
    public static void addWord(String word, NatureEnum nature) {
        logger.info("==== addWord@word:{},nature:{},weight:{} ====", word, nature.getNature(), nature.getWeight());
        if (!StringUtils.isBlank(word) && !word.equals("null")) {
            //大小括號問題
            if (word.contains("(") || word.contains(")")) {
                CustomDictionary.insert(word.replace("(", "(").replace(")", ")"), nature.getNature());
            }else if (word.contains("(") || word.contains(")")) {
                CustomDictionary.insert(word.replace("(", "(").replace(")", ")"), nature.getNature());
            }
            CustomDictionary.insert(word, nature.getNature());
        }else {
            logger.warn("==== addWord@ word({})為空 ====", word);
        }
    }

3. 動態(tài)刪除詞

/**
     * 刪除詞
     * @param forest
     * @param word
     */
    public static void deleteWord(String word) {
        logger.info("==== deleteWord@word:{} ====", word);
        if (!StringUtils.isBlank(word)) {
            CustomDictionary.remove(word);
        }else {
            logger.warn("==== deleteWord@word為空({}) ====", word);
        }
    }

4. 使用

/**
     * 分詞
     * @param content
     * @param forests
     * ToAnalysis精準(zhǔn)分詞
     * BaseAnalysis基礎(chǔ)分詞
     */
    public static SegmentResult segment(String content) {
        logger.info("==== segment@content:{} ====", content);
        SegmentResult segmentResult = new SegmentResult();
        List<Term> terms = HanLP.segment(content);
        Set<String> companySet = new HashSet<String>();
        
        for (Term term : terms) {
            String name = term.word;
            String nature = term.nature.toString();
            if (nature.equals(NatureEnum.Company.getNature())) {
                companySet.add(name);
            }
        }
        segmentResult.setCompanys(new ArrayList<String>(companySet));
        logger.info("==== segment@分詞結(jié)果:{},提取結(jié)果:{} ====", terms.toString(), segmentResult.toString());
        return segmentResult;
    }

5. 自定義詞典文件

詞典文件格式如下,依次是 詞艳狐、詞性定硝、權(quán)重
word nature weight

需要下載hanlp的data及hanlp.properties
https://github.com/hankcs/HanLP

data文件夾如下

image

hanlp.properties如下

#本配置文件中的路徑的根目錄,根目錄+其他路徑=完整路徑(支持相對路徑毫目,請參考:https://github.com/hankcs/HanLP/pull/254)
#Windows用戶請注意蔬啡,路徑分隔符統(tǒng)一使用/
root=/Users/FengZhen/Desktop/accumulate/分詞/HanLP/

#好了,以上為唯一需要修改的部分镀虐,以下配置項按需反注釋編輯箱蟆。

#核心詞典路徑
#CoreDictionaryPath=data/dictionary/CoreNatureDictionary.txt
#2元語法詞典路徑
#BiGramDictionaryPath=data/dictionary/CoreNatureDictionary.ngram.txt
#自定義詞典路徑,用;隔開多個自定義詞典刮便,空格開頭表示在同一個目錄空猜,使用“文件名 詞性”形式則表示這個詞典的詞性默認(rèn)是該詞性。優(yōu)先級遞減恨旱。
#所有詞典統(tǒng)一使用UTF-8編碼辈毯,每一行代表一個單詞,格式遵從[單詞] [詞性A] [A的頻次] [詞性B] [B的頻次] ... 如果不填詞性則表示采用詞典的默認(rèn)詞性搜贤。
CustomDictionaryPath=data/dictionary/custom/CustomDictionary.txt; Company.txt company; 現(xiàn)代漢語補充詞庫.txt; 全國地名大全.txt ns; 人名詞典.txt; 機構(gòu)名詞典.txt; 上海地名.txt ns;data/dictionary/person/nrf.txt nrf;
#停用詞詞典路徑
#CoreStopWordDictionaryPath=data/dictionary/stopwords.txt
#同義詞詞典路徑
#CoreSynonymDictionaryDictionaryPath=data/dictionary/synonym/CoreSynonym.txt
#人名詞典路徑
#PersonDictionaryPath=data/dictionary/person/nr.txt
#人名詞典轉(zhuǎn)移矩陣路徑
#PersonDictionaryTrPath=data/dictionary/person/nr.tr.txt
#繁簡詞典根目錄
#tcDictionaryRoot=data/dictionary/tc
#HMM分詞模型
#HMMSegmentModelPath=data/model/segment/HMMSegmentModel.bin
#分詞結(jié)果是否展示詞性
#ShowTermNature=true
#IO適配器谆沃,實現(xiàn)com.hankcs.hanlp.corpus.io.IIOAdapter接口以在不同的平臺(Hadoop、Redis等)上運行HanLP
#默認(rèn)的IO適配器如下仪芒,該適配器是基于普通文件系統(tǒng)的唁影。
#IOAdapter=com.hankcs.hanlp.corpus.io.FileIOAdapter
#感知機詞法分析器
#PerceptronCWSModelPath=data/model/perceptron/pku199801/cws.bin
#PerceptronPOSModelPath=data/model/perceptron/pku199801/pos.bin
#PerceptronNERModelPath=data/model/perceptron/pku199801/ner.bin
#CRF詞法分析器
#CRFCWSModelPath=data/model/crf/pku199801/cws.txt
#CRFPOSModelPath=data/model/crf/pku199801/pos.txt
#CRFNERModelPath=data/model/crf/pku199801/ner.txt
#更多配置項請參考 https://github.com/hankcs/HanLP/blob/master/src/main/java/com/hankcs/hanlp/HanLP.java#L59 自行添加

注意
1.hanlp.properties中的root路徑為本地data文件夾的父級路徑
2.準(zhǔn)備好的詞典文件可直接放入 data/dictionary/custom/下耕陷,然后再hanlp.properties中的 CustomDictionaryPath后添加該詞典文件名即可,如果不想在詞典文件中指定詞性据沈,也可在CustomDictionaryPath指定名字的同時哟沫,在后邊空格指定詞性。如上Company.txt company
3.在調(diào)用分詞方法時卓舵,hanlp會去自動加載自定義添加的詞典南用。速度比較慢,100w需要2m30s
4.自定義詞典文件更新時掏湾,需要將data/dictionary/custom/CustomDictionary.txt.bin刪掉裹虫。

Jieba的使用

1. 環(huán)境準(zhǔn)備

需要Python環(huán)境,需要pip

2. 安裝jieba

sudo pip install jieba

3. 使用


# encoding=utf-8
import jieba

seg_list = jieba.cut("我來到北京清華大學(xué)", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式

seg_list = jieba.cut("我來到北京清華大學(xué)", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精確模式

seg_list = jieba.cut("他來到了網(wǎng)易杭研大廈") # 默認(rèn)是精確模式
print(", ".join(seg_list))

seg_list = jieba.cut_for_search("小明碩士畢業(yè)于中國科學(xué)院計算所融击,后在日本京都大學(xué)深造") # 搜索引擎模式
print(", ".join(seg_list))

4.自定義詞典

# encoding=utf-8
import jieba
import jieba.posseg as pseg
import time

print("start-time" + time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))
file_name = "/home/jenkins/fz/segment/jieba/data/Company.txt"
jieba.load_userdict(file_name) # file_name 為文件類對象或自定義詞典的路徑
print("end-time" + time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())))

seg_list = jieba.cut("北京尚伯樂文化發(fā)展有限公司")
print("custom dic: " + "/ ".join(seg_list))

seg_list = pseg.cut(content) #帶詞性
for seg in seg_list:
print(seg)

Done

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末筑公,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子尊浪,更是在濱河造成了極大的恐慌匣屡,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拇涤,死亡現(xiàn)場離奇詭異捣作,居然都是意外死亡,警方通過查閱死者的電腦和手機鹅士,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門券躁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掉盅,你說我怎么就攤上這事也拜。” “怎么了趾痘?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵慢哈,是天一觀的道長。 經(jīng)常有香客問我永票,道長卵贱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任瓦侮,我火速辦了婚禮艰赞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘肚吏。我一直安慰自己方妖,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布罚攀。 她就那樣靜靜地躺著党觅,像睡著了一般雌澄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杯瞻,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天镐牺,我揣著相機與錄音,去河邊找鬼魁莉。 笑死睬涧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的旗唁。 我是一名探鬼主播畦浓,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼检疫!你這毒婦竟也來了讶请?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤屎媳,失蹤者是張志新(化名)和其女友劉穎夺溢,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烛谊,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡风响,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了丹禀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钞诡。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖湃崩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情接箫,我是刑警寧澤攒读,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站辛友,受9級特大地震影響薄扁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜废累,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一邓梅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧邑滨,春花似錦日缨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽面哥。三九已至,卻和暖如春毅待,著一層夾襖步出監(jiān)牢的瞬間尚卫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工尸红, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留吱涉,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓外里,卻偏偏與公主長得像怎爵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子级乐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 從本文開始疙咸,我們進入實戰(zhàn)部分。首先风科,我們按照中文自然語言處理流程的第一步獲取語料撒轮,然后重點進行中文分詞的學(xué)習(xí)...
    Element靜婷閱讀 880評論 0 0
  • 前言 從本文開始,我們進入實戰(zhàn)部分贼穆。首先题山,我們按照中文自然語言處理流程的第一步獲取語料,然后重點進行中文分詞的學(xué)習(xí)...
    lanlantian123閱讀 5,354評論 0 2
  • 前言 從本文開始故痊,我們進入實戰(zhàn)部分顶瞳。首先,我們按照中文自然語言處理流程的第一步獲取語料愕秫,然后重點進行中文分詞的學(xué)習(xí)...
    米飯超人閱讀 25,663評論 1 24
  • jieba分詞慨菱,學(xué)習(xí),為了全面了解該模塊戴甩,符喝,預(yù)設(shè)學(xué)習(xí)路線:官方文檔——優(yōu)秀博客文章——實踐學(xué)習(xí) 官方文檔部分 (文...
    竹林徒兒閱讀 4,129評論 1 12
  • 參考:Python 中文分詞組件 jiabaPython中文分詞 jieba 十五分鐘入門與進階jieba完整文檔...
    領(lǐng)悟悟悟閱讀 4,301評論 1 1