机器学习-文本处理
基礎知識
語料庫(corpus):
語料庫有三點特征
語料庫中存放的是在語言的實際使用中真實出現過的語言材料,因此例句庫通常不應算作語料庫;
語料庫是承載語言知識的基礎資源,但并不等于語言知識;
真實語料需要經過加工(分析和處理),才能成為有用的資源。
北京大學語料庫(http://icl.pku.edu.cn/ )
北大計算語言學研究所俞士汶教授主持,北大、富士通、人民日報社共同開發
《人民日報》1998年全部文本(約2600萬字)
完整的詞語切分和詞性標注信息
例子:
咱們/r 中國/ns 這么/r 大/a 的/u 一個/m 多/a 民族/n 的/u 國家/n 如果/c 不/d 團結/a ,/w 就/d 不/d 可能/v 發展/v 經濟
/n ,/w 人民/n 生活/n 水平/n 也/d 就/d 不/d 可能/v 得到/v 改善/vn 和/c 提高/vn
停用詞(stopword):
人類語言包含很多功能詞。與其他詞相比,功能詞沒有什么實際含義。最普遍的功能詞是限定詞("the"、"a"、"an"、"that"、和"those"),這些詞幫助在文本中描述名詞和表達概念,如地點或數量。介詞如:"over","under","above" 等表示兩個詞的相對位置。
這些功能詞的兩個特征促使在搜索引擎的文本處理過程中對其特殊對待。第一,這些功能詞極其普遍。記錄這些詞在每一個文檔中的數量需要很大的磁盤空間。第二,由于它們的普遍性和功能,這些詞很少單獨表達文檔相關程度的信息。如果在檢索過程中考慮每一個詞而不是短語,這些功能詞基本沒有什么幫助。
在信息檢索中,這些功能詞的另一個名稱是:停用詞(stopword)。稱它們為停用詞是因為在文本處理過程中如果遇到它們,則立即停止處理,將其扔掉。將這些詞扔掉減少了索引量,增加了檢索效率,并且通常都會提高檢索的效果。停用詞主要包括英文字符、數字、數學字符、標點符號及使用頻率特高的單漢字等。
Stop Words大致為如下兩類:
1、這些詞應用十分廣泛,在Internet上隨處可見,比如"Web"一詞幾乎在每個網站上均會出現,對這樣的詞搜索引擎無 法保證能夠給出真正相關的搜索結果,難以幫助縮小搜索范圍,同時還會降低搜索的效率;
2、這類就更多了,包括了語氣助詞、副詞、介詞、連接詞等,通常自身 并無明確的意義,只有將其放入一個完整的句子中才有一定作用,如常見的"的"、"在"之類。
詞袋BoW模型
Bag-of-words model (BoW model) 最早出現在自然語言處理(Natural Language Processing)和信息檢索(Information Retrieval)領域.。該模型忽略掉文本的語法和語序等要素,將其僅僅看作是若干個詞匯的集合,文檔中每個單詞的出現都是獨立的。BoW使用一組無序的單詞(words)來表達一段文字或一個文檔.。近年來,BoW模型副也被廣泛應用于計算機視覺中。
首先給出兩個簡單的文本文檔如下:
John likes to watch movies. Mary likes too.
John also likes to watch football games.
基于上述兩個文檔中出現的單詞,構建如下一個詞典 (dictionary):
{"John": 1, "likes": 2,"to": 3, "watch": 4, "movies": 5,"also": 6, "football": 7, "games": 8,"Mary": 9, "too": 10}
上面的詞典中包含10個單詞, 每個單詞有唯一的索引, 那么每個文本我們可以使用一個10維的向量來表示。如下:
[1, 2, 1, 1, 1, 0, 0, 0, 1, 1]
[1, 1,1, 1, 0, 1, 1, 1, 0, 0]
該向量與原來文本中單詞出現的順序沒有關系,而是詞典中每個單詞在文本中出現的頻率。
文本轉換
tf詞頻
from sklearn.feature_extraction.text import CountVectorizer X = ['我 愛 你','我 恨 你 恨 你'] y = [0,1] countCoder = CountVectorizer(token_pattern="[a-zA-Z|u4e00-u9fa5]+") X = countCoder.fit_transform(X) print(countCoder.get_feature_names()) print(X.toarray()) # ['你', '恨', '我', '愛'] # [[1 0 1 1] # [2 2 1 0]]
tf-idf
原始的詞項頻率會面臨這樣一個嚴重問題,即在和查詢進行相關度計算時,所有的詞項都被認為是同等重要的,實際上,某些詞項對于相關度計算來說幾乎沒有或很少有區分能力,例如在一個有關汽車工業的文檔集中,幾乎所有的文檔都會包含auto,但是auto就沒有區分的能力,因此下面我們提出一個機制來降低這些出現次數過多的詞在計算時的相關性.
一個直接的想法就是給文檔集進行統計頻數,較高詞頻的詞賦予較低的權重,這樣就很好的解決了這個問題.
IDF逆向文件頻率是一個詞語普遍重要性的度量。某一特定詞語的IDF,可以由總文件數目除以包含該詞語之文件的數目,再將得到的商取以10為底的對數得到.
例: X = [‘我 愛 你’,‘我 恨 你 恨 你’]
以“愛”為例,其df(愛,document1)=1
idf(愛)=
則,TF-IDF(愛,document1)=1*1.405
from sklearn.feature_extraction.text import TfidfVectorizer X = ['我 愛 你','我 恨 你 恨 你'] y = [0,1] tiCoder = TfidfVectorizer(norm=None,token_pattern="[a-zA-Z|u4e00-u9fa5]+") X = tiCoder.fit_transform(X) print(tiCoder.get_feature_names()) print(X.toarray()) # ['你', '恨', '我', '愛'] # [[ 1. 0. 1. 1.40546511] # [ 2. 2.81093022 1. 0. ]] # [[1 0 1 1] # [2 2 1 0]]
分詞工具:jieba
jieba:
“結巴”中文分詞:做最好的 Python 中文分詞組件,可用于中文句子/詞性分割、詞性標注、未登錄詞識別,支持用戶詞典等功能。能較好實現中文分詞,同時支持繁體分詞。
特點:
支持三種分詞模式:
精確模式: 試圖將句子最精確地切開,適合文本分析;
全模式:把句子中所有的可以成詞的詞語都掃描出來, 速度非常快,但是不能解決歧義;
搜索引擎模式:在精確模式的基礎上,對長詞再次切分,提高召回率,適合用于搜索引擎分詞。
支持繁體分詞
支持自定義詞典
算法:
基于前綴詞典實現高效的詞圖掃描,生成句子中漢字所有可能成詞情況所構成的有向無環圖 (DAG)
采用了動態規劃查找最大概率路徑, 找出基于詞頻的最大切分組合
對于未登錄詞,采用了基于漢字成詞能力的 HMM 模型,使用了 Viterbi 算法
1,主要功能
分詞
jieba.cut 方法接受三個輸入參數: 需要分詞的字符串;cut_all 參數用來控制是否采用全模式;HMM 參數用來控制是否使用 HMM 模型
jieba.cut_for_search 方法接受兩個參數:需要分詞的字符串;是否使用 HMM 模型。該方法適合用于搜索引擎構建倒排索引的分詞,粒度比較細
待分詞的字符串可以是 unicode 或 UTF-8 字符串、GBK 字符串。注意:不建議直接輸入 GBK 字符串,可能無法預料地錯誤解碼成 UTF-8
jieba.cut 以及 jieba.cut_for_search 返回的結構都是一個可迭代的 generator,可以使用 for 循環來獲得分詞后得到的每一個詞語(unicode),或者用
jieba.lcut 以及 jieba.lcut_for_search 直接返回 list
jieba.Tokenizer(dictionary=DEFAULT_DICT) 新建自定義分詞器,可用于同時使用不同詞典。jieba.dt 為默認分詞器,所有全局分詞相關函數都是該分詞器的映射。
# encoding=utf-8
import jieba
seg_list = jieba.cut("我來到北京清華大學", cut_all=True)
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
#Full Mode: 我/ 來到/ 北京/ 清華/ 清華大學/ 華大/ 大學
seg_list = jieba.cut("我來到北京清華大學", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精確模式
#Default Mode: 我/ 來到/ 北京/ 清華大學
seg_list = jieba.cut("他來到了網易杭研大廈") # 默認是精確模式
print(", ".join(seg_list))
#他, 來到, 了, 網易, 杭研, 大廈
seg_list = jieba.cut("小明碩士畢業于中國科學院計算所,后在日本京都大學深造") # 默認是精確模式print(", ".join(seg_list))
#小明, 碩士, 畢業, 于, 中國科學院, 計算所, ,, 后, 在, 日本京都大學, 深造
seg_list = jieba.cut("小明碩士畢業于中國科學院計算所,后在日本京都大學深造", cut_all=True) # 全模式print("Full Mode: " + "/ ".join(seg_list))#Full Mode: 小/ 明/ 碩士/ 畢業/ 于/ 中國/ 中國科學院/ 科學/ 科學院/ 學院/ 計算/ 計算所/ / / 后/ 在/ 日本/ 日本京都大學/ 京都/ 京都大學/ 大學/ 深造
seg_list = jieba.cut_for_search("小明碩士畢業于中國科學院計算所,后在日本京都大學深造") # 搜索引擎模式
print(", ".join(seg_list))
#小明, 碩士, 畢業, 于, 中國, 科學, 學院, 科學院, 中國科學院, 計算, 計算所, ,, 后, 在, 日本, 京都, 大學, 日本京都大學, 深造
添加自定義詞典
2,載入詞典:
開發者可以指定自己自定義的詞典,以便包含 jieba 詞庫里沒有的詞。雖然 jieba 有新詞識別能力,但是自行添加新詞可以保證更高的正確率
用法: jieba.load_userdict(file_name) # file_name 為文件類對象或自定義詞典的路徑
詞典格式和 dict.txt 一樣,一個詞占一行;每一行分三部分:詞語、詞頻(可省略)、詞性(可省略),用空格隔開,順序不可顛倒。file_name 若為路徑或二進制方式打開的文件,則文件必須為 UTF-8 編碼。
詞頻省略時使用自動計算的能保證分出該詞的詞頻。
例如: 創新辦 3 i
云計算 5
凱特琳 nz
更改分詞器(默認為jieba.dt)的tmp_dir和cache_file屬性,可分別指定緩存文件所在的文件夾及其文件名,用于受限的文件系統。
范例:
自定義詞典:https://github.com/fxsjy/jieba/blob/master/test/userdict.txt
用法示例:https://github.com/fxsjy/jieba/blob/master/test/test_userdict.py
之前: 李小福 / 是 / 創新 / 辦 / 主任 / 也 / 是 / 云 / 計算 / 方面 / 的 / 專家 /
加載自定義詞庫后: 李小福 / 是 / 創新辦 / 主任 / 也 / 是 / 云計算 / 方面 / 的 / 專家 /
(2) 調整詞典:
使用 add_word(word, freq=None, tag=None) 和 del_word(word) 可在程序中動態修改詞典。
使用 suggest_freq(segment, tune=True) 可調節單個詞語的詞頻,使其能(或不能)被分出來。
注意:自動計算的詞頻在使用 HMM 新詞發現功能時可能無效
test = "吳國忠臣伍子胥"
print("/".join(jieba.cut(test)))
print(jieba.get_FREQ("吳國忠"))
print(jieba.get_FREQ("臣"))
print(jieba.get_FREQ("吳國"))
print(jieba.get_FREQ("忠臣"))
jieba.add_word('忠臣',456) #更改忠臣詞頻為456
print("/".join(jieba.cut(test)))```
>>>
吳國忠/臣/伍子胥
14
5666
174
316
吳國/忠臣/伍子胥
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)))
「/臺中/」/正確/應該/不會/被/切開
3. 關鍵詞提取
(1) 基于 TF-IDF 算法的關鍵詞抽取
某個詞對文章的重要性越高,它的TF-IDF值就越大。所以,排在最前面的幾個詞,就是這篇文章的關鍵詞。
import jieba.analyse
jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
Sentence: 待提取的文本
topK : 返回幾個 TF/IDF 權重最大的關鍵詞,默認值為 20
withWeight: 是否一并返回關鍵詞權重值,默認值為 False
allowPOS: 僅包括指定詞性的詞,默認值為空,即不篩選
jieba.analyse.TFIDF(idf_path=None): 新建 TFIDF 實例,idf_path 為 IDF 頻率文件
代碼示例 (關鍵詞提取)
https://github.com/fxsjy/jieba/blob/master/test/extract_tags.py
關鍵詞提取所使用逆向文件頻率(IDF)文本語料庫可以切換成自定義語料庫的路徑
用法: jieba.analyse.set_idf_path(file_name) # file_name為自定義語料庫的路徑
自定義語料庫示例:https://github.com/fxsjy/jieba/blob/master/extra_dict/idf.txt.big
用法示例:https://github.com/fxsjy/jieba/blob/master/test/extract_tags_idfpath.py
關鍵詞提取所使用停止詞(Stop Words)文本語料庫可以切換成自定義語料庫的路徑
用法: jieba.analyse.set_stop_words(file_name) # file_name為自定義語料庫的路徑
自定義語料庫示例:https://github.com/fxsjy/jieba/blob/master/extra_dict/stop_words.txt
用法示例:https://github.com/fxsjy/jieba/blob/master/test/extract_tags_stop_words.py
關鍵詞一并返回關鍵詞權重值示例
用法示例:https://github.com/fxsjy/jieba/blob/master/test/extract_tags_with_weight.py
(2) 基于 TextRank 算法的關鍵詞抽取
jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=(‘ns’, ‘n’, ‘vn’, ‘v’)) 直接使用,接口相同,注意默認過濾詞性。
jieba.analyse.TextRank() 新建自定義 TextRank 實例
基本思想:(算法論文: TextRank: Bringing Order into Texts)
將待抽取關鍵詞的文本進行分詞
以固定窗口大小(默認為5,通過span屬性調整),詞之間的共現關系,構建圖
計算圖中節點的PageRank,注意是無向帶權圖
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)) for x, w in jieba.analyse.textrank(s, withWeight=True): print('%s %s' % (x, w))
---------------------------------------
TF-IDF
----------------------------------------歐亞 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----------------------------------------
TextRank
----------------------------------------
吉林 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
4. 詞性標注
jieba.posseg.POSTokenizer(tokenizer=None) 新建自定義分詞器,tokenizer 參數可指定內部使用的 jieba.Tokenizer 分詞器。jieba.posseg.dt 為默認詞性標注分詞器。
標注句子分詞后每個詞的詞性,采用和 ictclas 兼容的標記法。
用法示例
import jieba.posseg as pseg
words = pseg.cut("我愛北京天安門")
for word, flag in words:
print('%s %s' % (word, flag))
...
我 r
愛 v
北京 ns
天安門 ns
5. 并行分詞
原理:將目標文本按行分隔后,把各行文本分配到多個 Python 進程并行分詞,然后歸并結果,從而獲得分詞速度的可觀提升
基于 python 自帶的 multiprocessing 模塊,目前暫不支持 Windows
用法:
jieba.enable_parallel(4) # 開啟并行分詞模式,參數為并行進程數
jieba.disable_parallel() # 關閉并行分詞模式
例子:https://github.com/fxsjy/jieba/blob/master/test/parallel/test_file.py
實驗結果:在 4 核 3.4GHz Linux 機器上,對金庸全集進行精確分詞,獲得了 1MB/s 的速度,是單進程版的 3.3 倍。
注意:并行分詞僅支持默認分詞器 jieba.dt 和 jieba.posseg.dt。
中文文本分析
gensim
What is Gensim?
Gensim是一款開源的第三方Python工具包,用于從原始的非結構化的文本中,無監督地學習到文本隱層的主題向量表達。它支持包括TF-IDF,LSA,LDA,和word2vec在內的多種主題模型算法,支持流式訓練,并提供了諸如相似度計算,信息檢索等一些常用任務的API接口。
基本概念
語料(Corpus):一組原始文本的集合,這個集合是gensim的輸入,gensim會從這個語料中推斷出它的結構,主題等。從語料中推斷出的隱含結構,可以用來對一個新的文檔指定一個主題。我們把這個集合叫做訓練語料。這個訓練過程不需要人工標注的附加信息,所以主題分類是無監督的。在Gensim中,Corpus通常是一個可迭代的對象(比如列表)。每一次迭代返回一個可用于表達文本對象的稀疏向量。
向量(Vector):由一組文本特征構成的列表。是一段文本在Gensim中的內部表達。
稀疏向量(Sparse Vector):通常,可以略去向量中多余的0元素。此時,向量中的每一個元素是一個(key, value)的tuple。
模型(Model):是一個抽象的術語。定義了兩個向量空間的變換(即從文本的一種向量表達變換為另一種向量表達)。
Step 1. 訓練語料的預處理
訓練語料的預處理指的是將文檔中原始的字符文本轉換成Gensim模型所能理解的稀疏向量的過程。
通常,我們要處理的原生語料是一堆文檔的集合,每一篇文檔又是一些原生字符的集合。在交給Gensim的模型訓練之前,我們需要將這些原生字符解析成Gensim能處理的稀疏向量的格式。
由于語言和應用的多樣性,Gensim沒有對預處理的接口做出任何強制性的限定。通常,我們需要先對原始的文本進行分詞、去除停用詞等操作,得到每一篇文檔的特征列表。例如,在詞袋模型中,文檔的特征就是其包含的word:
texts = [['human', 'interface', 'computer'],
['survey', 'user', 'computer', 'system', 'response', 'time'],
['eps', 'user', 'interface', 'system'],
['system', 'human', 'system', 'eps'],
['user', 'response', 'time'],
['trees'],
['graph', 'trees'],
['graph', 'minors', 'trees'],
['graph', 'minors', 'survey']]
其中,corpus的每一個元素對應一篇文檔。
接下來,我們可以調用Gensim提供的API建立語料特征(此處即是word)的索引字典,并將文本特征的原始表達轉化成詞袋模型對應的稀疏向量的表達。依然以詞袋模型為例:
from gensim import corpora dictionary = corpora.Dictionary(texts) corpus = [dictionary.doc2bow(text) for text in texts] print(corpus[0]) # [(0, 1), (1, 1), (2, 1)]
其中,corpus的每一個元素對應一篇文檔。
最后,出于內存優化的考慮,Gensim支持文檔的流式處理。我們需要做的,只是將上面的列表封裝成一個Python迭代器;每一次迭代都返回一個稀疏向量即可。
class MyCorpus(object):
def __iter__(self):
for line in open('mycorpus.txt'):
# 假設每行有一個文檔,tokens以空格隔開
yield dictionary.doc2bow(line.lower().split()
Step 2. 主題向量的變換
對文本向量的變換是Gensim的核心。通過挖掘語料中隱藏的語義結構特征,最終可以變換出簡潔高效的文本向量。
在Gensim中,每一個向量變換的操作都對應著一個主題模型,例如上一小節提到的對應著詞袋模型的doc2bow變換。每一個模型又都是一個標準的Python對象。下面以TF-IDF模型為例,介紹Gensim模型的一般使用方法。
首先是模型對象的初始化。通常,Gensim模型都接受一段訓練語料(注意在Gensim中,語料對應著一個稀疏向量的迭代器)作為初始化的參數。顯然,越復雜的模型需要配置的參數越多。
from gensim import models tfidf = models.TfidfModel(corpus) print(tfidf[corpus[0]]) #[(0, 0.5773502691896257), (1, 0.5773502691896257), (2, 0.5773502691896257)]
其中,corpus是一個返回bow向量的迭代器。這兩行代碼將完成對corpus中出現的每一個特征的IDF值的計算。接下來,可以調用這個模型將任意一段語料(依然是bow向量的迭代器)轉化成TFIDF向量(的迭代器)。注意,這里的bow向量必須與訓練語料的bow向量共享同一個特征字典(即共享同一個向量空間)。
注意,同樣是出于內存的考慮,model[corpus]方法返回的是一個迭代器。如果要多次訪問model[corpus]的返回結果,可以先講結果向量序列化到磁盤上。也可以將訓練好的模型持久化到磁盤上,以便下一次使用:
tfidf.save("./model.tfidf")
tfidf = models.TfidfModel.load("./model.tfidf")
總結
- 上一篇: 18年出厂的五菱荣光s有几款车型?
- 下一篇: ubuntu屏幕扩展屏幕