文字相似度分析(基於jieba和gensim)
基礎概念
本文在進行文字相似度分析過程分為以下幾個部分進行,
- 文字分詞
- 語料庫製作
- 演算法訓練
- 結果預測
分析過程主要用兩個包來實現jieba,gensim
jieba:主要實現分詞過程
gensim:進行語料庫製作和演算法訓練
結巴(jieba)分詞
在自然語言處理領域中,分詞和提取關鍵詞都是對文字處理時通常要進行的步驟。用Python語言對英文文字進行預處理時可選擇NLTK庫,中文文字預處理可選擇jieba庫。結巴分詞是基於統計的分詞方法,它對給出大量已經分詞的文字,利用統計機器學習模型學習詞語切分的規律(稱為訓練),從而實現對未知文字的切分。例如最大概率分詞方法和最大熵分詞方法等。隨著大規模語料庫的建立,統計機器學習方法的研究和發展,基於統計的中文分詞方法漸漸成為了主流方法。
jieba分詞的三種模式:
- 精確模式:將句子最精確的分開,適合文字分析
- 全模式:句子中所有可以成詞的詞語都掃描出來,速度快,不能解決歧義
- 搜尋引擎模式:在精確的基礎上,對長詞再次切分,提高召回
結巴分詞的其他特點諸如:支援繁體分詞,支援自定義詞典,基於Trie樹結構實現高效的詞圖掃描,採用了動態規劃查詢最大概率路徑等特點。
jieba庫中分詞函式
1、jieba.cut()方法
引數string:需要接受分詞的字串。
引數cut_all:控制是否採用全模式分詞發,引數為True時表示採用全模式。
引數HMM:控制是否使用HMM模型,引數為True時表示使用HMM模型。
2、jieba.cut_for_search()
引數string:需要接受分詞的字串。
引數HMM:控制是否使用HMM模型,引數為True時表示使用HMM模型。
jieba.cut 以及 jieba.cut_for_search 返回的結構都是一個可迭代的 generator,可以使用 for 迴圈來獲得分詞後得到的每一個詞語。jieba.lcut和jieba.lcut_for_search引數和上面兩個方法一致但返回的是一個list。
python上的分詞輸出對比
import jieba string='上海市浦東新區世紀大道100號樓501' #精準模式 text_cut=jieba.cut(string) print(" ".join(text_cut)) #全模式 text_cut=jieba.cut(string,cut_all=True) print(" ".join(text_cut)) #搜尋模式 text_cut=jieba.cut_for_search(string) print(" ".join(text_cut))
三種模式的輸出結果:
精準模式:上海市浦東新區 世紀 大道 100 號樓 501
全模式:上海 上海市 上海市浦東新區 海市 浦東 浦東新區 新區 世紀 紀大 大道 100 號 樓 501
搜尋引擎模式:上海 海市 浦東 新區 上海市 上海市浦東新區 世紀 大道 100 號樓 501
jieba分詞自定義字典
在使用jieba時,使用者除了直接對文字進行分詞外,還可以自行新增新詞,已達到優化分詞效果的目的。
1、載入自定義字典jieba.load_userdict()
引數filename:為檔案類物件或自定義詞典的路徑
詞典格式分為3個部分:詞語、詞頻(可省略)、詞性(可省略),用空格隔開,順序不可顛倒。
file_name 若為路徑或二進位制方式開啟的檔案,則檔案必須為 UTF-8 編碼。
2、從字典中新增或刪除詞彙add_word、del_word
add_word(word,freq=None,tag=None),add_word有3個引數,新增詞名稱,詞頻,詞性
del_word(word),del_word只有一個引數詞語名稱
3、詞頻調整suggest_freq
suggest_freq(segment,tune=True)
調節單個詞語的詞頻,可以使其能(或不能)被分出來,詞頻越高在分詞時,能夠被分出來的概率越大。
python示例
import jieba #載入自定義詞典 jieba.load_userdict('word_dict.txt') #檢視使用者自定義詞典中的內容 print(jieba.user_word_tag_tab) #往自定義詞典中新增新詞 jieba.add_word('人民廣場',freq=5,tag='n') #新增新詞後的結果 print(jieba.user_word_tag_tab) string='上海市浦東新區世紀大道100號樓501' text_cut=jieba.cut(string) print(" ".join(text_cut)) #調整詞頻,重新分詞 jieba.suggest_freq(('上海市','浦東新區'),tune=True) text_cut=jieba.cut(string) print(" ".join(text_cut))
輸出結果:
載入詞典內容:{'世紀大道': 'n', '浦東新區 2 ': 'n', '世紀公園 3 ': 'n'}
新增新詞後:{'世紀大道': 'n', '浦東新區 2 ': 'n', '世紀公園 3 ': 'n', '人民廣場': 'n'}
結巴原始字典庫,分詞結果:上海市浦東新區 世紀 大道 100 號樓 501
使用自定義詞典後,分詞結果:上海市浦東新區 世紀大道 100 號樓 501
調整詞頻後,分詞結果:上海市 浦東新區 世紀大道 100 號樓 501
結巴分詞官方文件:
https://pypi.org/project/jieba/結巴分詞github地址:
https://github.com/fxsjy/jiebaGensim
Gensim是一款開源的第三方Python工具包,用於從原始的非結構化的文字中,無監督地學習到文字隱層的主題向量表達。
它支援包括TF-IDF,LSA,LDA,和word2vec在內的多種主題模型演算法。
相關概念
-
語料(Corpus):一組原始文字的集合,用於無監督地訓練文字主題的隱層結構。在Gensim中,Corpus通常是一個可迭代的物件(比如列表)。每一次迭代返回一個可用於表達文字物件的稀疏向量。
-
向量(Vector):由一組文字特徵構成的列表。是一段文字在Gensim中的內部表達。在向量空間模型中,每個文件被表示成了一組特徵,比如,一個單一的特徵可能被視為一個問答對。
-
稀疏向量(SparseVector):通常,大部分問題的答案都是0,為了節約空間,我們會從文件表示中省略他們,向量中的每一個元素是一個(key, value)的元組,比如(1,3),(2,4),(5,0),其中(5,0)是一個稀疏向量,在表示是會被忽略。
-
模型(Model):是一個抽象的術語。定義了兩個向量空間的變換(即從文字的一種向量表達變換為另一種向量表達)。
把幾個概念組織起來表述:gensim可以通過讀取一段語料,輸出一個向量,表示文件中的一個詞。為了節約空間,通常稀疏的詞向量會被忽略,剩下的詞向量則可以用來訓練各種模型,即從原有的文字表達轉向另一種文字表達。
語料庫製作
語料庫製作主要包含兩個過程:
獲取詞袋:本文主要來自於結巴分詞結果
向量轉換:對獲取的詞袋進行向量轉換
1、獲取詞袋函式 gensim.corpora.Dictionary()
gensim.corpora.dictionary.Dictionary可以為每個出現在語料庫中的單詞分配了一個獨一無二的整數編號id。這個操作收集了單詞計數及其他相關的統計資訊。
python示例
import jieba import gensim print(jieba.user_word_tag_tab) string=['上海市浦東新區世紀大道100號樓501','上海市世紀大道100號樓501'] texts_list=[] for sentence in string: sentence_list=[ word for word in jieba.cut(sentence)] texts_list.append(sentence_list) dictionary=gensim.corpora.Dictionary(texts_list) print(dictionary) print(dictionary.token2id)
輸出結果:
Dictionary(7 unique tokens: ['100', '501', '上海市浦東新區', '世紀', '號樓']...)
{'100': 0, '501': 1, '上海市浦東新區': 2, '世紀': 3, '號樓': 4, '大道': 5, '上海市': 6}
第一行結果告訴我們語料庫中有7個不同的單詞,這表明每個文件將會用7個數字表示(即7維向量)。
第二行結果是檢視單詞與編號之間的對映關係。
2、向量轉換 dictionary.doc2bow()
函式doc2bow() 簡單地對每個不同單詞的出現次數進行了計數,並將單詞轉換為其編號,然後以稀疏向量的形式返回結果。
python示例
corpus = [dictionary.doc2bow(doc) for doc in texts_list] print(corpus)
輸出結果:
[[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1)], [(0, 1), (1, 1), (3, 1), (4, 1), (5, 1), (6, 1)]]
以上結果中,表示兩個字串中,每個詞的id以及它對應的出現頻次,比如第一個元組(0,1)代表的是編號為0的詞在第一個字串中出現一次。
演算法訓練
下面我們使用tf-idf演算法對上面的語料庫進行建模,識別不同文字的相似度。
python示例
#測試字串 test_string='浦東新區世紀大道100號樓501' test_doc_list=[word for word in jieba.cut(test_string)] test_doc_vec=dictionary.doc2bow(test_doc_list) # 使用TF-IDF模型對語料庫建模 tfidf = gensim.models.TfidfModel(corpus) #分析測試文件與已存在的每個訓練文字的相似度 index = gensim.similarities.SparseMatrixSimilarity(tfidf[corpus], num_features=len(dictionary.keys())) sim = index[tfidf[test_doc_vec]] print(sim)
輸出結果:
[ 0.63650501 0.63650501 0. ]
表示測試文字與訓練的3個文字相似度分佈0.63 0.63 0
以上就是使用jieba和gensim文字相似度的簡單實現.
gensim官方文件:
https://pypi.org/project/gensim/