Python 命名實體識別(NER) 庫 使用指南

一、前言

最近工作中需要使用命名實體識別來做一版人名及機構名的預識別demo,評估了獨立訓練一套NER模型所耗費的標註成本巨大,加上目前只是對該需求進行demo版本的開發,所以花了一段時間對目前現有的開源 NER 工具包進行了調研及優缺點評估。

這次主要使用的開源 NER 工具包有:

  • StanfordCoreNLP

 https://stanfordnlp.github.io/CoreNLP/

  • Hanlp

http://www.hanlp.com/

  • foolNLTK

https://github.com/rockyzhengwu/FoolNLTK

  • LTP

http://www.ltp-cloud.com/

現在將安裝步驟,使用方法,及一些優缺點分析記錄在此。


二、StanfordCoreNLP

StanfordCoreNLP 是斯坦福大學發佈的 NLP 處理工具,StanfordCoreNLP 的源碼使用 Java 編寫,目前 Python 可以用兩種方法進行調用,一種是使用 StanfordCoreNLP 庫,是對 StanfordCoreNLP 進行了 Python 封裝。而另一種方法是直接使用 Stanford 官方發佈的 Python 版本 StanfordNLP。這裏介紹第一種方式。

1.安裝方法

(1) 首先  pip install stanfordcorenlp 

(2) 其次 由於其源碼爲 JAVA 編寫,所以需要 JDK1.8 及以上版本的支持,下載安裝 JDK1.8

(3) 下載 StanfordCoreNLP 的相關文件 ,主要是 相關語言的 JAR 模型,以及 CoreNLP 3.9.2

(4) 解壓下載好的 CoreNLP 文件,並將 JAR 模型放在加壓好的文件夾中

以上就完成了安裝準備工作,可以開始使用 StanfordCoreNLP 來進行分詞,詞性標註,命名實體識別等工作了。

2.調用方法

接下來,記錄一下 使用 StanfordCoreNLP 進行 NER 時的調用方法。

from stanfordcorenlp import StanfordCoreNLP

# 加載模型
stanford_model = StanfordCoreNLP(r'./stanford-corenlp-full-2018-02-27', lang='zh')

text = "張三和李四在2019年3月23日在北京的騰訊技術有限公司一起開會。"

res = stanford_model.ner(text)

調用方法很簡單,res 的輸出爲:

[('張三', 'PERSON'), ('和', 'O'), ('李四', 'PERSON'), ('在', 'O'), ('2019年', 'DATE'), ('3月', 'DATE'), ('23日', 'DATE'), ('在', 'O'), ('北京', 'STATE_OR_PROVINCE'), ('的', 'O'), ('騰訊', 'ORGANIZATION'), ('技術', 'ORGANIZATION'), ('有限', 'ORGANIZATION'), ('公司', 'ORGANIZATION'), ('一起', 'O'), ('開會', 'O'), ('。', 'O')]

 可以看出,對人名、時間、地名、機構名的識別還是比較準確的。

StanfordCoreNLP 也提供了線上體驗的 Demo,可以在 這裏 進行 NER 的線上體驗。


三、Hanlp

Hanlp 的源碼也是由 Java 編寫,所以這意味着你在使用 Hanlp 時,也需要安裝 JDK 1.8,以及配置你的 Java 環境變量。

1.安裝方法

(1) 首先 pip install pyhanlp

(2)  首次使用時會自動下載 data 數據,若下載過慢的話,可以在 GitHub下的配置頁面 進行手動配置,自行下載 data 數據,將其放在 pyhanlp 安裝目錄的 static 目錄下面。

以上就完成了安裝準備工作,可以開始使用 Hanlp 來進行分詞,詞性標註,命名實體識別等工作了。

2.調用方法

調用方法同樣很簡單。

from pyhanlp import *

# 加載模型
ha_model = HanLP.newSegment()

text = "張三和李四在2019年3月23日在北京的騰訊技術有限公司一起開會。"

res = ha_model.seg(text)
print(res)

 使用 HanLP.newSegment() 方法實現的其實是詞性標註的功能,當需要識別人名、地名、機構名時,需要在方法後加上相應的後綴。

# 中國人名識別
ha_model = HanLP.newSegment().enableNameRecognize(true)

# 地名識別
ha_model = HanLP.newSegment().enablePlaceRecognize(true)

# 機構名識別
ha_model = HanLP.newSegment().enableOrganizationRecognize(true)

調用結果:

[張/q, 三和/nz, 李/ng, 四/m, 在/p, 2019/m, 年/qt, 3月/t, 23/m, 日/b, 在/p, 北京/ns, 的/ude1, 騰訊/ntc, 技術/n, 有限公司/nis, 一起/s, 開會/vi, 。/w]

 從結果來看,Hanlp 的命名實體識別的效果較 StanfordCoreNLP 來看不是很令人滿意,而我在使用 Hanlp 來做 命名實體識別的任務時,也是通過歸類詞性來實現的,例如將詞性爲 “ni”, "nis", "nic", "nit" 的詞語都歸納爲機構名。具體的 Hanlp 的詞性對照表在 這裏


四、FoolNLTK

FoolNLTK 基於 Bi-LSTM 訓練而成,在調用時會依賴 TensorFlow,在分詞,詞性標註,以及命名實體識別時都有較高的準確率。

1.安裝方法

FoolNLTK 的安裝也很方便,只需要 pip install foolnltk,依賴的 TensorFlow 會自動安裝,不需要配置其他環境以及下載其他模型。

2.調用方法

FoolNLTK 的調用也非常簡單,不需要預加載模型,直接 import 後就可以進行預測,第一次預測時會對模型進行加載,會消耗一定的時間,後續調用模型時的速度都很快。

    import fool

    text = "張三和李四在2019年3月23日在北京的騰訊技術有限公司一起開會。"

    res = fool.analysis(text)
    print(res)

調用結果:

([[('張三', 'nr'), ('和', 'c'), ('李四', 'nr'), ('在', 'p'), ('2019年', 't'), ('3月', 't'), ('23日', 't'), ('在', 'p'), ('北京', 'ns'), ('的', 'ude'), ('騰訊', 'nz'), ('技術', 'n'), ('有限公司', 'n'), ('一起', 's'), ('開會', 'vi'), ('。', 'wj')]], [[(0, 3, 'person', '張三'), (3, 6, 'person', '李四'), (6, 17, 'time', '2019年3月23日'), (17, 20, 'location', '北京'), (20, 29, 'company', '騰訊技術有限公司')]])

 調用結果中的第一項爲詞性識別的結果,第二項爲命名實體識別的結果,可以看到識別的效果還是非常好的。


五、LTP

LTP 爲哈工大開發的中文 NLP 開源工具,這裏使用的也是 LTP 的 Python 封裝版本 pyltp。

1.安裝方法

(1) pip install pyltp 首先 pip 安裝 pyltp 庫。

(2) 在 LTP 的模型頁面 下載模型,這裏要注意 pyltp 庫版本需要和模型的版本對應。在 這裏 查看版本的對應情況。當版本不對應時,加載模型會出現報錯。

2.調用方法

調用 LTP 時,也需要首先對模型進行加載。

    from pyltp import Segmentor, Postagger, NamedEntityRecognizer
    import os

    LTP_DATA_DIR = r'C:/Users/1V994W2/PycharmProjects/ppt_ner/ltp_data_v3.4.0'

    segmentor = Segmentor()
    segmentor.load(os.path.join(LTP_DATA_DIR, "cws.model"))

    postagger = Postagger()
    postagger.load(os.path.join(LTP_DATA_DIR, "pos.model"))

    recognizer = NamedEntityRecognizer()
    recognizer.load(os.path.join(LTP_DATA_DIR, "ner.model"))


    text = "張三和李四在2019年3月23日在北京的騰訊技術有限公司一起開會。"

    words = segmentor.segment(text)
    print(list(words))
    postags = postagger.postag(words)
    print(list(postags))
    netags = recognizer.recognize(words, postags)
    print(list(netags))

需要注意的是,在試用 LTP 進行命名實體識別時,不能像其他開源庫一樣,直接輸入句子進行識別,而首先需要調用 LTP 的分詞工具 Segmentor 對文本進行分詞,在使用詞性標註工具 Postagger 對分詞好的句子進行詞性標註,最後在進行命名實體識別。LTP_DATA_DIR 爲下載的 LTP 模型解壓後的路徑,進行各類 NLP 任務時需要加載對應的模型。

調用結果:

['張三', '和', '李四', '在', '2019年', '3月', '23日', '在', '北京', '的', '騰訊', '技術', '有限公司', '一起', '開會', '。']
['nh', 'c', 'nh', 'p', 'nt', 'nt', 'nt', 'p', 'ns', 'u', 'nz', 'n', 'n', 'd', 'v', 'wp']
['S-Nh', 'O', 'S-Nh', 'O', 'O', 'O', 'O', 'O', 'S-Ns', 'O', 'B-Ni', 'I-Ni', 'E-Ni', 'O', 'O', 'O']

 以上分別爲分詞,詞性標註於命名實體識別的結果。LTP 採用 BIESO 標註體系。B 表示實體開始詞,I表示實體中間詞,E表示實體結束詞,S表示單獨成實體,O表示不構成命名實體。LTP 提供的命名實體類型爲:人名(Nh)、地名(Ns)、機構名(Ni)。B、I、E、S位置標籤和實體類型標籤之間用一個橫線 - 相連;O標籤後沒有類型標籤。詳細標註請參考 命名實體識別標註集 。


六、Bagging

四種 NER 的開源庫互有優勢,所以在使用時,我採用 Bagging 的方法將它們集成起來使用,每種庫給出自己的識別結果,多數投標得出最終的識別結果。

最終經過部門標註同學的標註,集成的 NER 識別工具的準確率達到 75% 左右,雖然離上線要求還有一定的差距,但使用其對文本進行預標註,可以大幅加快標註同學的數據標註時間,也算是起到了一定的節約人力成本的作用。

 

 

如有問題歡迎指正,轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章