pyhanlp 實體命名識別

pyhanlp中的命名實體識別
對於分詞而言,命名實體識別是一項非常重要的功能,當然發現新詞同樣重要(這部分內容被我放在之後的“提取關鍵詞、短語提取與自動摘要、新詞識別”與再之後的案例中了。

首先是一個簡單的例子,展示一下命名實體識別的效果。之後是正式內容:

簡單的展示例子
from pyhanlp import *
"""
HanLP開啓命名實體識別

"""

音譯人名示例

CRFnewSegment = HanLP.newSegment("crf")
term_list = CRFnewSegment.seg("譯智社的田豐要說的是這只是一個hanlp命名實體識別的例子")
print(term_list)

print("\n========== 命名實體開啓與關閉對比試驗 ==========\n")
sentences =[
"北川景子參演了林詣彬導演的《速度與激情3》",
"林志玲亮相網友:確定不是波多野結衣?",
"龜山千廣和近藤公園在龜山公園裏喝酒賞花",
]

通過HanLP 進行全局設置,但是部分分詞器本身可能不支持某項功能

部分分詞器本身對某些命名實體識別效果較好

HanLP.Config.japaneseNameRecognize = False

viterbiNewSegment = HanLP.newSegment("viterbi").enableJapaneseNameRecognize(True)
CRFnewSegment_new = HanLP.newSegment("crf").enableJapaneseNameRecognize(True)

segSentence

CRFnewSegment_2.seg2sentence(sentences)

for sentence in sentences:
print("crf : ",CRFnewSegment.seg(sentence))
print("crf_new : ",CRFnewSegment_new.seg(sentence))
print("viterbi : ",viterbiNewSegment.seg(sentence))

[譯智社/n, 的/u, 田豐/nr, 要/v, 說/v, 的/u, 是/v, 這/r, 只/d, 是/v, 一個/m, hanlp命名/vn, 實體/n, 識別/v, 的/u, 例子/n]

========== 命名實體開啓與關閉對比試驗 ==========

crf : [北川/ns, 景子/n, 參演/v, 了/u, 林詣彬/nr, 導演/n, 的/u, 《/w, 速度/n, 與/c, 激情/n, 3/m, 》/w]
crf_new : [北川/ns, 景子/n, 參演/v, 了/u, 林詣彬/nr, 導演/n, 的/u, 《/w, 速度/n, 與/c, 激情/n, 3/m, 》/w]
viterbi : [北川景子/nrj, 參演/v, 了/ule, 林詣彬/nr, 導演/nnt, 的/ude1, 《/w, 速度/n, 與/cc, 激情/n, 3/m, 》/w]
crf : [林志玲/nr, 亮相/v, 網友/n, :/w, 確定/v, 不/d, 是/v, 波多野/n, 結衣/n, ?/w]
crf_new : [林志玲/nr, 亮相/v, 網友/n, :/w, 確定/v, 不/d, 是/v, 波多野/n, 結衣/n, ?/w]
viterbi : [林志玲/nr, 亮相/vi, 網友/n, :/w, 確定/v, 不是/c, 波多野結衣/nrj, ?/w]
crf : [龜/v, 山/n, 千/m, 廣/q, 和/c, 近藤/a, 公園/n, 在/p, 龜山公園/ns, 裏/f, 喝/v, 酒/n, 賞/v, 花/n]
crf_new : [龜/v, 山/n, 千/m, 廣/q, 和/c, 近藤/a, 公園/n, 在/p, 龜山公園/ns, 裏/f, 喝/v, 酒/n, 賞/v, 花/n]
viterbi : [龜山千廣/nrj, 和/cc, 近藤公園/nrj, 在/p, 龜山/nz, 公園/n, 裏/f, 喝酒/vi, 賞花/nz]

正式內容
中國人名識別
說明

目前分詞器基本上都默認開啓了中國人名識別,比如HanLP.segment()接口中使用的分詞器等等,用戶不必手動開啓;上面的代碼只是爲了強調。
有一定的誤命中率,比如誤命中關鍵年,則可以通過在data/dictionary/person/nr.txt加入一條關鍵年 A 1來排除關鍵年作爲人名的可能性,也可以將關鍵年作爲新詞登記到自定義詞典中。
如果你通過上述辦法解決了問題,歡迎向我提交pull request,詞典也是寶貴的財富。
建議NLP用戶使用感知機或CRF詞法分析器,精度更高。
算法詳解

《實戰HMM-Viterbi角色標註中國人名識別》

中文人名識別

def demo_chinese_name_recognition(sentences):
segment = HanLP.newSegment().enableNameRecognize(True);
for sentence in sentences:
term_list = segment.seg(sentence)
print(term_list)
print([i.word for i in term_list])

sentences = [
"簽約儀式前,秦光榮、李紀恆、仇和等一同會見了參加簽約的企業家。",
"武大靖創世界紀錄奪冠,中國代表團平昌首金",
"區長莊木弟新年致辭",
"朱立倫:兩岸都希望共創雙贏 習朱歷史會晤在即",
"陝西首富吳一堅被帶走 與×××妻子有交集",
"據美國之音電臺網站4月28日報道,8歲的凱瑟琳·克羅爾(鳳甫娟)和很多華裔美國小朋友一樣,小小年紀就開始學小提琴了。她的媽媽是位虎媽麼?",
"凱瑟琳和露西(廬瑞媛),跟她們的哥哥們有一些不同。",
"王國強、高峯、×××、張朝陽光着頭、韓寒、小四",
"張浩和胡健康復員回家了",
"王總和小麗結婚了",
"編劇邵鈞林和稽道青說",
"這裏有關天培的有關事蹟",
"龔學平等領導說,×××生前杜絕超生",]
demo_chinese_name_recognition(sentences)

print("\n========== 中文人名 基本默認已開啓 ==========\n")
print(CRFnewSegment.seg(sentences[0]))

[簽約/vi, 儀式/n, 前/f, ,/w, 秦光榮/nr, 、/w, 李紀恆/nr, 、/w, 仇和/nr, 等/udeng, 一同/d, 會見/v, 了/ule, 參加/v, 簽約/vi, 的/ude1, 企業家/nnt, 。/w]
['簽約', '儀式', '前', ',', '秦光榮', '、', '李紀恆', '、', '仇和', '等', '一同', '會見', '了', '參加', '簽約', '的', '企業家', '。']
[武大靖/nr, 創/v, 世界/n, 紀錄/n, 奪冠/vi, ,/w, 中國/ns, 代表團/n, 平昌/ns, 首/q, 金/b]
['武大靖', '創', '世界', '紀錄', '奪冠', ',', '中國', '代表團', '平昌', '首', '金']
[區長/nnt, 莊木弟/nr, 新年/t, 致辭/vi]
['區長', '莊木弟', '新年', '致辭']
[朱立倫/nr, :/w, 兩岸/n, 都/d, 希望/v, 共創/v, 雙贏/n, /w, 習/v, 朱/ag, 歷史/n, 會晤/vn, 在即/vi]
['朱立倫', ':', '兩岸', '都', '希望', '共創', '雙贏', ' ', '習', '朱', '歷史', '會晤', '在即']
[陝西/ns, 首富/n, 吳一堅/nr, 被/pbei, 帶走/v, /w, 與/cc, ×××/nr, 妻子/n, 有/vyou, 交集/v]
['陝西', '首富', '吳一堅', '被', '帶走', ' ', '與', '×××', '妻子', '有', '交集']
[據/p, 美國之音/n, 電臺/nis, 網站/n, 4月/t, 28/m, 日/b, 報道/v, ,/w, 8/m, 歲/qt, 的/ude1, 凱瑟琳/nr, ·/w, 克/q, 羅爾/nr, (/w, 鳳甫娟/nr, )/w, 和/cc, 很多/m, 華裔/n, 美國/nsf, 小朋友/n, 一樣/uyy, ,/w, 小小/z, 年紀/n, 就/d, 開始/v, 學/v, 小提琴/n, 了/ule, 。/w, 她/rr, 的/ude1, 媽媽/n, 是/vshi, 位/q, 虎媽/nz, 麼/y, ?/w]
['據', '美國之音', '電臺', '網站', '4月', '28', '日', '報道', ',', '8', '歲', '的', '凱瑟琳', '·', '克', '羅爾', '(', '鳳甫娟', ')', '和', '很多', '華裔', '美國', '小朋友', '一樣', ',', '小小', '年紀', '就', '開始', '學', '小提琴', '了', '。', '她', '的', '媽媽', '是', '位', '虎媽', '麼', '?']
[凱瑟琳/nr, 和/cc, 露西/nr, (/w, 廬瑞媛/nr, )/w, ,/w, 跟/p, 她們/rr, 的/ude1, 哥哥/n, 們/k, 有/vyou, 一些/m, 不同/a, 。/w]
['凱瑟琳', '和', '露西', '(', '廬瑞媛', ')', ',', '跟', '她們', '的', '哥哥', '們', '有', '一些', '不同', '。']
[王國強/nr, 、/w, 高峯/n, 、/w, ×××/n, 、/w, 張朝陽/nr, 光/n, 着/uzhe, 頭/n, 、/w, 韓寒/nr, 、/w, 小/a, 四/m]
['王國強', '、', '高峯', '、', '×××', '、', '張朝陽', '光', '着', '頭', '、', '韓寒', '、', '小', '四']
[張浩/nr, 和/cc, 胡健康/nr, 復員/v, 回家/vi, 了/ule]
['張浩', '和', '胡健康', '復員', '回家', '了']
[王總/nr, 和/cc, 小麗/nr, 結婚/vi, 了/ule]
['王總', '和', '小麗', '結婚', '了']
[編劇/nnt, 邵鈞林/nr, 和/cc, 稽道青/nr, 說/v]
['編劇', '邵鈞林', '和', '稽道青', '說']
[這裏/rzs, 有/vyou, 關天培/nr, 的/ude1, 有關/vn, 事蹟/n]
['這裏', '有', '關天培', '的', '有關', '事蹟']
[龔學平/nr, 等/udeng, 領導/n, 說/v, ,/w, ×××/nr, 生前/t, 杜絕/v, 超生/vi]
['龔學平', '等', '領導', '說', ',', '×××', '生前', '杜絕', '超生']

========== 中文人名 基本默認已開啓 ==========

[簽約/vn, 儀式/n, 前/f, ,/w, 秦光榮/nr, 、/w, 李紀恆/nr, 、/w, 仇和/nr, 等/u, 一同/d, 會見/v, 了/u, 參加/v, 簽約/v, 的/u, 企業家/n, 。/w]

音譯人名識別
說明

目前分詞器基本上都默認開啓了音譯人名識別,用戶不必手動開啓;上面的代碼只是爲了強調。
算法詳解

《層疊隱馬模型下的音譯人名和日本人名識別》

音譯人名識別

sentences = [
"一桶冰水當頭倒下,微軟的比爾蓋茨、Facebook的扎克伯格跟桑德博格、亞馬遜的貝索斯、蘋果的庫克全都不惜溼身入鏡,這些硅谷的科技人,飛蛾撲火似地犧牲演出,其實全爲了慈善。",
"世界上最長的姓名是簡森·喬伊·亞歷山大·比基·卡利斯勒·達夫·埃利奧特·福克斯·伊維魯莫·馬爾尼·梅爾斯·帕特森·湯普森·華萊士·普雷斯頓。",
]

segment = HanLP.newSegment().enableTranslatedNameRecognize(True)
for sentence in sentences:
term_list = segment.seg(sentence)
print(term_list)

print("\n========== 音譯人名 默認已開啓 ==========\n")
print(CRFnewSegment.seg(sentences[0]))

[一桶/nz, 冰水/n, 當頭/vi, 倒下/v, ,/w, 微軟/ntc, 的/ude1, 比爾蓋茨/nrf, 、/w, Facebook/nx, 的/ude1, 扎克伯格/nr, 跟/p, 桑德博格/nrf, 、/w, 亞馬遜/nrf, 的/ude1, 貝索斯/nrf, 、/w, 蘋果/nf, 的/ude1, 庫克/nr, 全都/d, 不惜/v, 溼身/nz, 入鏡/nz, ,/w, 這些/rz, 硅谷/ns, 的/ude1, 科技/n, 人/n, ,/w, 飛蛾/n, 撲火/vn, 似/vg, 地/ude2, 犧牲/v, 演出/vn, ,/w, 其實/d, 全/a, 爲了/p, 慈善/a, 。/w]
[世界/n, 上/f, 最長/d, 的/ude1, 姓名/n, 是/vshi, 簡森/nr, ·/w, 喬伊/nr, ·/w, 亞歷山大/nr, ·/w, 比基/nr, ·/w, 卡利斯/nr, 勒/v, ·/w, 達夫·埃利奧特·福克斯·伊維魯莫·馬爾尼·梅爾斯·帕特森·湯普森·華萊士·普雷斯頓/nrf, 。/w]

========== 音譯人名 默認已開啓 ==========

[一桶/m, 冰水/n, 當頭/d, 倒下/v, ,/w, 微軟/a, 的/u, 比爾蓋茨/n, 、/w, Facebook/l, 的/u, 扎克伯格/n, 跟/p, 桑德博格/n, 、/w, 亞馬遜/nr, 的/u, 貝索斯/nr, 、/w, 蘋果/n, 的/u, 庫克/nr, 全都/d, 不惜/v, 溼身/n, 入鏡/v, ,/w, 這些/r, 硅谷/n, 的/u, 科技/n, 人/n, ,/w, 飛蛾/v, 撲火似/v, 地/u, 犧牲/v, 演出/v, ,/w, 其實/d, 全/d, 爲了/p, 慈善/a, 。/w]

日本人名識別
說明

目前標準分詞器默認關閉了日本人名識別,用戶需要手動開啓;這是因爲日本人名的出現頻率較低,但是又消耗性能。
算法詳解

《層疊隱馬模型下的音譯人名和日本人名識別》

日語人名識別

def demo_japanese_name_recognition(sentences):

segment = HanLP.newSegment().enableJapaneseNameRecognize(True)
for sentence in sentences:
    term_list = segment.seg(sentence)
    print(term_list)
    print([i.word for i in term_list])

sentences =[
"北川景子參演了林詣彬導演的《速度與激情3》",
"林志玲亮相網友:確定不是波多野結衣?",
"龜山千廣和近藤公園在龜山公園裏喝酒賞花",
]
demo_japanese_name_recognition(sentences)
print("\n========== 日文人名 標準分詞器默認未開啓 ==========\n")
print(CRFnewSegment.seg(sentences[0]))

[北川景子/nrj, 參演/v, 了/ule, 林詣彬/nr, 導演/nnt, 的/ude1, 《/w, 速度/n, 與/cc, 激情/n, 3/m, 》/w]
['北川景子', '參演', '了', '林詣彬', '導演', '的', '《', '速度', '與', '激情', '3', '》']
[林志玲/nr, 亮相/vi, 網友/n, :/w, 確定/v, 不是/c, 波多野結衣/nrj, ?/w]
['林志玲', '亮相', '網友', ':', '確定', '不是', '波多野結衣', '?']
[龜山千廣/nrj, 和/cc, 近藤公園/nrj, 在/p, 龜山/nz, 公園/n, 裏/f, 喝酒/vi, 賞花/nz]
['龜山千廣', '和', '近藤公園', '在', '龜山', '公園', '裏', '喝酒', '賞花']

========== 日文人名 標準分詞器默認未開啓 ==========

[北川/ns, 景子/n, 參演/v, 了/u, 林詣彬/nr, 導演/n, 的/u, 《/w, 速度/n, 與/c, 激情/n, 3/m, 》/w]

地名識別
說明

目前標準分詞器都默認關閉了地名識別,用戶需要手動開啓;這是因爲消耗性能,其實多數地名都收錄在核心詞典和用戶自定義詞典中。
在生產環境中,能靠詞典解決的問題就靠詞典解決,這是最高效穩定的方法。
建議對命名實體識別要求較高的用戶使用感知機詞法分析器。
算法詳解

《實戰HMM-Viterbi角色標註地名識別》

演示數詞與數量詞識別

sentences = [
"十九元套餐包括什麼",
"九千九百九十九朵玫瑰",
"壹佰塊都不給我",
"9012345678只螞蟻",
"牛奶三〇〇克*2",
"ChinaJoy“掃黃”細則露胸超2釐米罰款",
]

StandardTokenizer = JClass("com.hankcs.hanlp.tokenizer.StandardTokenizer")

StandardTokenizer.SEGMENT.enableNumberQuantifierRecognize(True)
for sentence in sentences:
print(StandardTokenizer.segment(sentence))

print("\n========== 演示數詞與數量詞 默認未開啓 ==========\n")
CRFnewSegment.enableNumberQuantifierRecognize(True)
print(CRFnewSegment.seg(sentences[0]))

[十九元/mq, 套餐/n, 包括/v, 什麼/ry]
[九千九百九十九朵/mq, 玫瑰/n]
[壹佰塊/mq, 都/d, 不/d, 給/p, 我/rr]
[9012345678只/mq, 螞蟻/n]
[牛奶/nf, 三〇〇克/mq, */w, 2/m]
[ChinaJoy/nx, “/w, 掃黃/vi, ”/w, 細則/n, 露/v, 胸/ng, 超/v, 2釐米/mq, 罰款/vi]

========== 演示數詞與數量詞 默認未開啓 ==========

[十九/m, 元/q, 套餐/n, 包括/v, 什麼/r]

機構名識別
說明

目前分詞器默認關閉了機構名識別,用戶需要手動開啓;這是因爲消耗性能,其實常用機構名都收錄在核心詞典和用戶自定義詞典中。
HanLP的目的不是演示動態識別,在生產環境中,能靠詞典解決的問題就靠詞典解決,這是最高效穩定的方法。
建議對命名實體識別要求較高的用戶使用感知機詞法分析器。
算法詳解

《層疊HMM-Viterbi角色標註模型下的機構名識別》

機構名識別

sentences = [
"我在上海林原科技有限公司兼職工作,",
"我經常在臺川喜宴餐廳吃飯,",
"偶爾去開元地中海影城看電影。",
]

Segment = JClass("com.hankcs.hanlp.seg.Segment")
Term = JClass("com.hankcs.hanlp.seg.common.Term")

segment = HanLP.newSegment().enableOrganizationRecognize(True)
for sentence in sentences:
term_list = segment.seg(sentence)
print(term_list)

print("\n========== 機構名 標準分詞器已經全部關閉 ==========\n")
print(CRFnewSegment.seg(sentences[0]))

segment = HanLP.newSegment('crf').enableOrganizationRecognize(True)

[我/rr, 在/p, 上海/ns, 林原科技有限公司/nt, 兼職/vn, 工作/vn, ,/w]
[我/rr, 經常/d, 在/p, 臺川喜宴餐廳/nt, 吃飯/vi, ,/w]
[偶爾/d, 去/vf, 開元地中海影城/nt, 看/v, 電影/n, 。/w]

========== 機構名 標準分詞器已經全部關閉 ==========

地名識別
說明

目前標準分詞器都默認關閉了地名識別,用戶需要手動開啓;這是因爲消耗性能,其實多數地名都收錄在核心詞典和用戶自定義詞典中。
在生產環境中,能靠詞典解決的問題就靠詞典解決,這是最高效穩定的方法。
建議對命名實體識別要求較高的用戶使用感知機詞法分析器。
算法詳解

《實戰HMM-Viterbi角色標註地名識別》

地名識別

def demo_place_recognition(sentences):

segment = HanLP.newSegment().enablePlaceRecognize(True)
for sentence in sentences:
    term_list = segment.seg(sentence)
    print(term_list)
    print([i.word for i in term_list])

sentences = ["藍翔給寧夏固原市彭陽縣紅河鎮黑牛溝村捐贈了挖掘機"]
demo_place_recognition(sentences)

print("\n========== 地名 默認已開啓 ==========\n")
print(CRFnewSegment.seg(sentences[0]))

[藍翔/nr, 給/p, 寧夏/ns, 固原市/ns, 彭陽縣/ns, 紅河鎮/ns, 黑牛溝村/ns, 捐贈/v, 了/ule, 挖掘機/n]
['藍翔', '給', '寧夏', '固原市', '彭陽縣', '紅河鎮', '黑牛溝村', '捐贈', '了', '挖掘機']

========== 地名 默認已開啓 ==========

[藍翔/v, 給/v, 寧夏/ns, 固原市/ns, 彭陽縣/ns, 紅河鎮/ns, 黑牛溝村/ns, 捐贈/v, 了/u, 挖掘機/n]

URL 識別
自動識別URL,該部分是在demo中發現的,但是原作者並沒有在文檔中提到這個,該部分可以發現URL,測試發現其他分類器應該是默認不開啓這個的,而且config中並沒有開啓該功能的選項,因此這應該是一個額外的類。我建議如果有需要的,你可以嘗試先利用URLTokenizer獲取URL,然後添加進用戶詞典。或者直接使用其他工具或者自定義函數解決該問題。

URL 識別

text = '''HanLP的項目地址是https://github.com/hankcs/HanLP,
發佈地址是https://github.com/hankcs/HanLP/releases,
我有時候會在www.hankcs.com上面發佈一些消息,
我的微博是http://weibo.com/hankcs/,會同步推送hankcs.com的新聞。
聽說.中國域名開放申請了,但我並沒有申請hankcs.中國,因爲窮……
'''

Nature = SafeJClass("com.hankcs.hanlp.corpus.tag.Nature")
Term = SafeJClass("com.hankcs.hanlp.seg.common.Term")
URLTokenizer = SafeJClass("com.hankcs.hanlp.tokenizer.URLTokenizer")

term_list = URLTokenizer.segment(text)
print(term_list)
for term in term_list:
if term.nature == Nature.xu:
print(term.word)

[HanLP/nx, 的/ude1, 項目/n, 地址/n, 是/vshi, https://github.com/hankcs/HanLP/xu, ,/w,
/w, /w, 發佈/v, 地址/n, 是/vshi, https://github.com/hankcs/HanLP/releases/xu, ,/w,
/w, /w, 我/rr, 有時候/d, 會/v, 在/p, www.hankcs.com/xu, 上面/f, 發佈/v, 一些/m, 消息/n, ,/w,
/w, /w, 我/rr, 的/ude1, 微博/n, 是/vshi, http://weibo.com/hankcs//xu, ,/w, 會/v, 同步/vd, 推送/nz, hankcs.com/xu, 的/ude1, 新聞/n, 。/w,
/w, /w, 聽說/v, ./w, 中國/ns, 域名/n, 開放/v, 申請/v, 了/ule, ,/w, 但/c, 我/rr, 並/cc, 沒有/v, 申請/v, hankcs.中國/xu, ,/w, 因爲/c, 窮/a, ……/w,
/w, /w]
https://github.com/hankcs/HanLP
https://github.com/hankcs/HanLP/releases
www.hankcs.com
http://weibo.com/hankcs/
hankcs.com
hankcs.中國

文章來源於Font Tian的博客

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