知識提取是要解決結構化數據生成的問題。可是廣義上講,知識提取是數據質量提高中的一環,各類提高數據質量的方法,均可以視爲某種知識提取。學術上通常是用天然語言處理的方法,但在實踐中一般是利用規則。html
咱們要熟悉的概念和工具備 (假設你們已經熟悉了Python
)python
正則表達式
:正則表達式是字符串處理的基本功。經常使用工具re
.數據爬取、數據清洗、實體提取、關係提取,都離不開regex。中文分詞和詞性標註
:分詞也是後續處理的基礎。經常使用工具jieba
中文包.分詞作得好,核心祕密在詞庫,算法的影響反而不太大。分詞是會出錯的。不過有些場合(好比檢索排序),只要錯誤是一向的,影響也不是太大。分詞後面能夠用規則來彌補。詞性(Part of Speech, POS)就是中學你們學過的動詞、名詞、形容詞等等的詞的分類。通常的分詞工具都會有詞性標註的選項。命名實體識別
:用nltk
調用Stanford NLP
包這裏咱們可使用Python
的re
包(re – Regular Expressions)進行正則匹配git
>>> import re
# 利用match方法匹配,若是匹配成功,返回一個Match對象,不然返回None
>>> re.match(r'^\d{3}\-\d{3,8}$', '010-12345')
<_sre.SRE_Match object at 0x1026e18b8>
複製代碼
當咱們在Python
中使用正則表達式時,re
模塊內部會幹兩件事情: 1.編譯正則表達式,若是正則表達式的字符串自己不合法,會報錯; 2.用編譯後的正則表達式去匹配字符串。 若是一個正則表達式要重複使用幾千次,出於效率的考慮,咱們能夠預編譯該正則表達式,接下來重複使用時就不須要編譯這個步驟了,直接匹配:github
>>> import re
# 編譯:
>>> re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')
# 使用:
>>> re_telephone.match('010-12345').groups()
('010', '12345')
>>> re_telephone.match('010-8086').groups()
('010', '8086')
# 匹配文本中全部email地址
mail_reg = re.compile(
u''' ((((e-)?mail|(e|E-)?MAIL|(e|E-)?Mail)|郵箱){1}(:|-|:|\ )*)? (([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5}){1,25}) ''', re.X
)
mail = mail_reg.findall(each_line.encode('utf-8').decode('utf-8'))
複製代碼
更多方法見
re官方文檔 或者 Ubuntu上的Wiki ^_^web
咱們能夠用jieba
中文分詞包進行分詞和標註,本文檔主要講jieba使用,另外還有PyNLPIR 提供 NLPIR/ICTCLAS漢語分詞的Python接口,看這個教程 pynlpir.readthedocs.io/en/latest/t… ,中文詞性標記集 github.com/memect/kg-b…正則表達式
支持三種分詞模式:算法
精確模式
,試圖將句子最精確地切開,適合文本分析;全模式
,把句子中全部的能夠成詞的詞語都掃描出來, 速度很是快,可是不能解決歧義;搜索引擎模式
,在精確模式的基礎上,對長詞再次切分,提升召回率,適合用於搜索引擎分詞。支持繁體分詞ubuntu
支持自定義詞典python3.x
代碼對 Python 2/3 均兼容api
easy_install jieba
或者 pip install jieba
/ pip3 install jieba
python setup.py install
import jieba
來引用jieba.cut
方法接受三個輸入參數: 須要分詞的字符串;cut_all 參數用來控制是否採用全模式;HMM 參數用來控制是否使用 HMM 模型jieba.cut_for_search
方法接受兩個參數:須要分詞的字符串;是否使用 HMM 模型。該方法適合用於搜索引擎構建倒排索引的分詞,粒度比較細jieba.cut
以及 jieba.cut_for_search
返回的結構都是一個可迭代的 generator,可使用 for 循環來得到分詞後獲得的每個詞語(unicode),或者用jieba.lcut
以及 jieba.lcut_for_search
直接返回 listjieba.Tokenizer(dictionary=DEFAULT_DICT)
新建自定義分詞器,可用於同時使用不一樣詞典。jieba.dt
爲默認分詞器,全部全局分詞相關函數都是該分詞器的映射。代碼示例
# encoding=utf-8
import jieba
seg_list = jieba.cut("我來到北京清華大學", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
seg_list = jieba.cut("我來到北京清華大學", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精確模式
seg_list = jieba.cut("他來到了網易杭研大廈") # 默認是精確模式
print(", ".join(seg_list))
seg_list = jieba.cut_for_search("小明碩士畢業於中國科學院計算所,後在日本京都大學深造") # 搜索引擎模式
print(", ".join(seg_list))
複製代碼
輸出:
【全模式】: 我/ 來到/ 北京/ 清華/ 清華大學/ 華大/ 大學
【精確模式】: 我/ 來到/ 北京/ 清華大學
【新詞識別】:他, 來到, 了, 網易, 杭研, 大廈 (此處,「杭研」並無在詞典中,可是也被Viterbi算法識別出來了)
【搜索引擎模式】: 小明, 碩士, 畢業, 於, 中國, 科學, 學院, 科學院, 中國科學院, 計算, 計算所, 後, 在, 日本, 京都, 大學, 日本京都大學, 深造
複製代碼
dict.txt
同樣,一個詞佔一行;每一行分三部分:詞語、詞頻(可省略)、詞性(可省略),用空格隔開,順序不可顛倒。file_name
若爲路徑或二進制方式打開的文件,則文件必須爲 UTF-8 編碼。自定義詞典:userdict.txt
創新辦 3 i
雲計算 5
凱特琳 nz
複製代碼
更改分詞器(默認爲 jieba.dt
)的 tmp_dir
和 cache_file
屬性,可分別指定緩存文件所在的文件夾及其文件名,用於受限的文件系統。
範例:
# 導入jieba
import jieba
# 導入自定義詞典
jieba.load_userdict("userdict.txt")
test_sent = (
"李小福是創新辦主任也是雲計算方面的專家; 什麼是八一雙鹿\n"
"例如我輸入一個帶「韓玉賞鑑」的標題,在自定義詞庫中也增長了此詞爲N類\n"
"「臺中」正確應該不會被切開。mac上可分出「石墨烯」;此時又能夠分出來凱特琳了。"
)
words = jieba.cut(test_sent)
print('/'.join(words))
# 導入自定義詞典前的分詞狀況:
李小福/是/創新/辦/主任/也/是/雲/計算/方面/的/專家/;/ /什麼/是/八/一雙/鹿/
/例如/我/輸入/一個/帶/「/韓玉/賞鑑/」/的/標題/,/在/自定義詞/庫中/也/增長/了/此/詞爲/N/類/
/「/臺/中/」/正確/應該/不會/被/切開/。/mac/上/可/分出/「/石墨/烯/」/;/此時/又/能夠/分出/來凱/特琳/了/。
# 導入自定義詞典後的分詞狀況:
李小福/是/創新辦/主任/也/是/雲計算/方面/的/專家/;/ /什麼/是/八一雙鹿/
/例如/我/輸入/一個/帶/「/韓玉賞鑑/」/的/標題/,/在/自定義詞/庫中/也/增長/了/此/詞爲/N/類/
/「/臺中/」/正確/應該/不會/被/切開/。/mac/上/可/分出/「/石墨/烯/」/;/此時/又/能夠/分出/來/凱特琳/了/。
複製代碼
add_word(word, freq=None, tag=None)
和 del_word(word)
可在程序中動態修改詞典。suggest_freq(segment, tune=True)
可調節單個詞語的詞頻,使其能(或不能)被分出來。修改詞典:
# 導入jieba
import jieba
# 導入自定義詞典
jieba.load_userdict("userdict.txt")
# 增長自定義詞
jieba.add_word('石墨烯')
jieba.add_word('凱特琳')
jieba.del_word('自定義詞')
test_sent = (
"李小福是創新辦主任也是雲計算方面的專家; 什麼是八一雙鹿\n"
"例如我輸入一個帶「韓玉賞鑑」的標題,在自定義詞庫中也增長了此詞爲N類\n"
"「臺中」正確應該不會被切開。mac上可分出「石墨烯」;此時又能夠分出來凱特琳了。"
)
words = jieba.cut(test_sent)
print('/'.join(words))
# 增長自定義詞前的分詞狀況:
李小福/是/創新辦/主任/也/是/雲計算/方面/的/專家/;/ /什麼/是/八一雙鹿/
/例如/我/輸入/一個/帶/「/韓玉賞鑑/」/的/標題/,/在/自定義詞/庫中/也/增長/了/此/詞爲/N/類/
/「/臺中/」/正確/應該/不會/被/切開/。/mac/上/可/分出/「/石墨/烯/」/;/此時/又/能夠/分出/來/凱特琳/了/。
# 增長自定義詞後的分詞狀況:
李小福/是/創新辦/主任/也/是/雲計算/方面/的/專家/;/ /什麼/是/八一雙鹿/
/例如/我/輸入/一個/帶/「/韓玉賞鑑/」/的/標題/,/在/自定義/詞庫/中/也/增長/了/此/詞爲/N/類/
/「/臺中/」/正確/應該/不會/被/切開/。/mac/上/可/分出/「/石墨烯/」/;/此時/又/能夠/分出/來/凱特琳/了/。
複製代碼
調整詞頻:
>>> print('/'.join(jieba.cut('若是放到post中將出錯。', HMM=False)))
若是/放到/post/中將/出錯/。
>>> jieba.suggest_freq(('中', '將'), True)
494
>>> print('/'.join(jieba.cut('若是放到post中將出錯。', HMM=False)))
若是/放到/post/中/將/出錯/。
>>> print('/'.join(jieba.cut('「臺中」正確應該不會被切開', HMM=False)))
「/臺/中/」/正確/應該/不會/被/切開
>>> jieba.suggest_freq('臺中', True)
69
>>> print('/'.join(jieba.cut('「臺中」正確應該不會被切開', HMM=False)))
「/臺中/」/正確/應該/不會/被/切開
複製代碼
import jieba.analyse
代碼示例 :
s = "此外,公司擬對全資子公司吉林歐亞置業有限公司增資4.3億元,增資後,吉林歐亞置業註冊資本由7000萬元增長到5億元。吉林歐亞置業主要經營範圍爲房地產開發及百貨零售等業務。目前在建吉林歐亞城市商業綜合體項目。2013年,實現營業收入0萬元,實現淨利潤-139.13萬元。"
for x, w in jieba.analyse.extract_tags(s, withWeight=True):
print('%s %s' % (x, w))
歐亞 0.7300142700289363
吉林 0.659038184373617
置業 0.4887134522112766
萬元 0.3392722481859574
增資 0.33582401985234045
4.3 0.25435675538085106
7000 0.25435675538085106
2013 0.25435675538085106
139.13 0.25435675538085106
實現 0.19900979900382978
綜合體 0.19480309624702127
經營範圍 0.19389757253595744
億元 0.1914421623587234
在建 0.17541884768425534
全資 0.17180164988510638
註冊資本 0.1712441526
百貨 0.16734460041382979
零售 0.1475057117057447
子公司 0.14596045237787234
營業 0.13920178509021275
複製代碼
關鍵詞提取所使用逆向文件頻率(IDF)文本語料庫能夠切換成自定義語料庫的路徑
關鍵詞提取所使用中止詞(Stop Words)文本語料庫能夠切換成自定義語料庫的路徑
算法論文: TextRank: Bringing Order into Texts
import jieba
import jieba.posseg
import jieba.analyse
s = "此外,公司擬對全資子公司吉林歐亞置業有限公司增資4.3億元,增資後,吉林歐亞置業註冊資本由7000萬元增長到5億元。吉林歐亞置業主要經營範圍爲房地產開發及百貨零售等業務。目前在建吉林歐亞城市商業綜合體項目。2013年,實現營業收入0萬元,實現淨利潤-139.13萬元。"
for x, w in jieba.analyse.textrank(s, withWeight=True):
print('%s %s' % (x, w))
吉林 1.0
歐亞 0.9966893354178172
置業 0.6434360313092776
實現 0.5898606692859626
收入 0.43677859947991454
增資 0.4099900531283276
子公司 0.35678295947672795
城市 0.34971383667403655
商業 0.34817220716026936
業務 0.3092230992619838
在建 0.3077929164033088
營業 0.3035777049319588
全資 0.303540981053475
綜合體 0.29580869172394825
註冊資本 0.29000519464085045
有限公司 0.2807830798576574
零售 0.27883620861218145
百貨 0.2781657628445476
開發 0.2693488779295851
經營範圍 0.2642762173558316
複製代碼
jieba.posseg.POSTokenizer(tokenizer=None)
新建自定義分詞器,tokenizer
參數可指定內部使用的 jieba.Tokenizer
分詞器。jieba.posseg.dt
爲默認詞性標註分詞器。用法示例:
>>> import jieba.posseg as pseg
>>> words = pseg.cut("我愛北京天安門")
>>> for word, flag in words:
... print('%s %s' % (word, flag))
...
我 r
愛 v
北京 ns
天安門 ns
複製代碼
原理:將目標文本按行分隔後,把各行文本分配到多個 Python 進程並行分詞,而後歸併結果,從而得到分詞速度的可觀提高
基於 python 自帶的 multiprocessing 模塊,目前暫不支持 Windows
用法:
jieba.enable_parallel(4)
# 開啓並行分詞模式,參數爲並行進程數jieba.disable_parallel()
# 關閉並行分詞模式代碼示例:
import jieba
jieba.enable_parallel(4)
import jieba.posseg as pseg
def cuttest(test_sent):
result = pseg.cut(test_sent)
for w in result:
print(w.word, "/", w.flag, ", ", end=' ')
print("")
if __name__ == "__main__":
cuttest("這是一個伸手不見五指的黑夜。我叫孫悟空,我愛北京,我愛Python和C++。")
cuttest("我不喜歡日本和服。")
cuttest("雷猴迴歸人間。")
cuttest("工信處女幹事每個月通過下屬科室都要親口交代24口交換機等技術性器件的安裝工做")
cuttest("我須要廉租房")
cuttest("永和服裝飾品有限公司")
cuttest("我愛北京天安門")
cuttest("abc")
cuttest("隱馬爾可夫")
cuttest("雷猴是個好網站")
cuttest("「Microsoft」一詞由「MICROcomputer(微型計算機)」和「SOFTware(軟件)」兩部分組成")
cuttest("草泥馬和欺實馬是今年的流行詞彙")
cuttest("伊藤洋華堂總府店")
cuttest("中國科學院計算技術研究所")
cuttest("羅密歐與朱麗葉")
cuttest("我購買了道具和服裝")
cuttest("PS: 我以爲開源有一個好處,就是可以敦促本身不斷改進,避免敞帚自珍")
cuttest("湖北省石首市")
cuttest("湖北省十堰市")
cuttest("總經理完成了這件事情")
cuttest("電腦修好了")
複製代碼
實驗結果:在 4 核 3.4GHz Linux 機器上,對金庸全集進行精確分詞,得到了 1MB/s 的速度,是單進程版的 3.3 倍。
注意:並行分詞僅支持默認分詞器 jieba.dt
和 jieba.posseg.dt
。
result = jieba.tokenize(u'永和服裝飾品有限公司')
for tk in result:
print("word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]))
複製代碼
word 永和 start: 0 end:2
word 服裝 start: 2 end:4
word 飾品 start: 4 end:6
word 有限公司 start: 6 end:10
複製代碼
result = jieba.tokenize(u'永和服裝飾品有限公司', mode='search')
for tk in result:
print("word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]))
複製代碼
word 永和 start: 0 end:2
word 服裝 start: 2 end:4
word 飾品 start: 4 end:6
word 有限 start: 6 end:8
word 公司 start: 8 end:10
word 有限公司 start: 6 end:10
複製代碼
NLTK 是一款著名的 Python 天然語言處理(Natural Language Processing, NLP)工具包,在其收集的大量公開數據集、模型上提供了全面、易用的接口,涵蓋了分詞、詞性標註(Part-Of-Speech tag, POS-tag)、命名實體識別(Named Entity Recognition, NER)、句法分析(Syntactic Parse)等各項 NLP 領域的功能。 Stanford NLP 是由斯坦福大學的 NLP 小組開源的 Java 實現的 NLP 工具包,一樣對 NLP 領域的各個問題提供瞭解決辦法。 如今的 NLTK 3.2中,經過封裝提供了 Stanford NLP 中的如下幾個功能:
分詞
詞性標註
命名實體識別
句法分析
,依存句法分析
操做步驟: 參考原帖:www.jianshu.com/p/4b3c7e757… 在python中下載並安裝nltk:github.com/nltk/nltk 下載stanford相關包,這裏選用3.6.0版本(即2015-12-09更新版本): stanford-ner-2015-12-09.zip(nlp.stanford.edu/software/CR… stanford-parser-full-2015-12-09.zip(nlp.stanford.edu/software/le… stanford-postagger-full-2015-12-09.zip(nlp.stanford.edu/software/ta… stanford-segmenter-2015-12-09.zip(nlp.stanford.edu/software/se… 所有zip包解壓並存放於/opt目錄下 對stanford-segmenter-2015-12-09文件文件夾中stanford-segmenter-3.6.0.jar作軟鏈接,命令行輸入
ln -s stanford-segmenter-3.6.0.jar stanford-segmenter.jar
複製代碼
在~/.bashrc文件中添加以下內容:
export STANFORD_SEGMENTER_PATH="/opt/stanford-segmenter-2015-12-09"
export CLASSPATH="$CLASSPATH:$STANFORD_SEGMENTER_PATH/stanford-segmenter.jar:$STANFORD_SEGMENTER_PATH/slf4j-api.jar"
export STANFORD_POSTAGGER_PATH="/opt/stanford-postagger-full-2015-12-09"
export CLASSPATH="$CLASSPATH:$STANFORD_POSTAGGER_PATH/stanford-postagger.jar"
export STANFORD_PARSER_PATH="/opt/stanford-parser-full-2015-12-09"
export CLASSPATH="$CLASSPATH:$STANFORD_PARSER_PATH/stanford-parser.jar:$STANFORD_PARSER_PATH/stanford-parser-3.6.0-models.jar"
export STANFORD_NER_PATH="/opt/stanford-ner-2015-12-09"
export CLASSPATH="$CLASSPATH:$STANFORD_NER_PATH/stanford-ner.jar"
export STANFORD_MODELS="$STANFORD_NER_PATH/classifiers:$STANFORD_POSTAGGER_PATH/models"
複製代碼
命令行輸入
source ~/.bashrc
複製代碼
啓動python便可,示例(注意python2.x和python3.x的語法區別):
# coding: utf-8
from nltk.tokenize import StanfordSegmenter
segmenter = StanfordSegmenter(path_to_sihan_corpora_dict="/root/stanford-segmenter-2015-12-09/data/",path_to_model="/root/stanford-segmenter-2015-12-09/data/pku.gz",path_to_dict="/root/stanford-segmenter-2015-12-09/data/dict-chris6.ser.gz")
res = segmenter.segment(u"北海已成爲中國對外開放中升起的一顆明星")
print(type(res))
print(res)
複製代碼