1. 程式人生 > >python實現gensim.word2vec模型訓練例項

python實現gensim.word2vec模型訓練例項

word2vec在NLP領域的運用比較多,最近看了網上的例子覺得挺有意思的,就自己動手實踐了一下。

簡單總結:

所謂的word vector,就是指將單詞向量化,將某個單詞用特定的向量來表示。將單詞轉化成對應的向量以後,就可以將其應用於各種機器學習的演算法中去。一般來講,詞向量主要有兩種形式,分別是稀疏向量和密集向量。

所謂稀疏向量,又稱為one-hot representation,就是用一個很長的向量來表示一個詞,向量的長度為詞典的大小N,向量的分量只有一個1,其他全為0,1的位置對應該詞在詞典中的索引[1]。舉例來說,如果有一個詞典[“麵條”,”方便麵”,”獅子”],那麼“麵條”對應的詞向量就是[1,0,0],“方便麵”對應的詞向量就是[0,1,0]。這種表示方法不需要繁瑣的計算,簡單易得,但是缺點也不少,比如長度過長(這會引發維數災難),以及無法體現出近義詞之間的關係,比如“麵條”和“方便麵”顯然有非常緊密的關係,但轉化成向量[1,0,0]和[0,1,0]以後,就看不出兩者有什麼關係了,因為這兩個向量相互正交。當然了,用這種稀疏向量求和來表示文件向量效果還不錯,清華的長文字分類工具THUCTC使用的就是此種表示方法

至於密集向量,又稱distributed representation,即分散式表示。最早由Hinton提出,可以克服one-hot representation的上述缺點,基本思路是通過訓練將每個詞對映成一個固定長度的短向量,所有這些向量就構成一個詞向量空間,每一個向量可視為該空間上的一個點[1]。此時向量長度可以自由選擇,與詞典規模無關。這是非常大的優勢。還是用之前的例子[“麵條”,”方便麵”,”獅子”],經過訓練後,“麵條”對應的向量可能是[1,0,1,1,0],而“方便麵”對應的可能是[1,0,1,0,0],而“獅子”對應的可能是[0,1,0,0,1]。這樣“麵條”向量乘“方便麵”=2,而“麵條”向量乘“獅子”=0 。這樣就體現出麵條與方便麵之間的關係更加緊密,而與獅子就沒什麼關係了。這種表示方式更精準的表現出近義詞之間的關係,比之稀疏向量優勢很明顯。可以說這是深度學習在NLP領域的第一個運用(雖然我覺得並沒深到哪裡去)

回過頭來看word2vec,其實word2vec做的事情很簡單,大致來說,就是構建了一個多層神經網路,然後在給定文字中獲取對應的輸入和輸出,在訓練過程中不斷修正神經網路中的引數,最後得到詞向量。


訓練模型主要步驟包括:

第一節:讀取檔案

import jieba,re,os
from gensim.models import word2vec
import logging  
#jieba.load_userdict("data\\userdict.txt")  

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO,filename='test_01.log')  
filename = 'test_01.txt'   #測試文字
pre,ext = os.path.splitext(filename)   #輸入檔案分開字首,字尾   pre=test_01   ext=.txt
corpus = pre + '_seg' + ext    #訓練語料為按行分詞後的文字檔案    corpus=test_01_seg.txt
fin = open(filename,encoding='utf8').read().strip(' ').strip('\n').replace('\n\n','\n')   #strip()取出首位空格,和換行符,用\n替換\n\n
stopwords = set(open('test_01停用詞.txt',encoding='utf8').read().strip('\n').split('\n'))   #讀入停用詞

對日誌處理,logging.basiConfig函式的各個引數可以參考:

  1. logging.basicConfig函式各引數:  
  2. filename: 指定日誌檔名  
  3. filemode: 和file函式意義相同,指定日誌檔案的開啟模式,'w'或'a'  
  4. format: 指定輸出的格式和內容,format可以輸出很多有用資訊,如上例所示:  
  5.  %(levelno)s: 列印日誌級別的數值  
  6.  %(levelname)s: 列印日誌級別名稱  
  7.  %(pathname)s: 列印當前執行程式的路徑,其實就是sys.argv[0]  
  8.  %(filename)s: 列印當前執行程式名  
  9.  %(funcName)s: 列印日誌的當前函式  
  10.  %(lineno)d: 列印日誌的當前行號  
  11.  %(asctime)s: 列印日誌的時間  
  12.  %(thread)d: 列印執行緒ID  
  13.  %(threadName)s: 列印執行緒名稱  
  14.  %(process)d: 列印程序ID  
  15.  %(message)s: 列印日誌資訊  
  16. datefmt: 指定時間格式,同time.strftime()  
  17. level: 設定日誌級別,預設為logging.WARNING  
  18. stream: 指定將日誌的輸出流,可以指定輸出到sys.stderr,sys.stdout或者檔案,預設輸出到sys.stderr,當stream和filename同時指定時,stream被忽略 

第二:分詞,將訓練文字中的詞做處理,不能包含停用詞中的詞,以及長度少於等於1的詞,去標點,

所謂停用詞,就是出現頻率太高的詞,如逗號,句號等等,以至於沒有區分度。

text = ' '.join([x for x in jieba.lcut(fin) if x not in stopwords and len(x)>1 and x != '\n'])  #去掉停用詞中的詞,去掉長度小於等於1的詞
print(text)   
results = re.sub('[()::?“”《》,。!·、\d ]+',' ',text)  #去標點
open(corpus,'w+',encoding='utf8').write(results)   #按行分詞後存為訓練語料

第三:用預處理好的語料 訓練模型

#3.訓練模型
sentences = word2vec.LineSentence(corpus)  # 載入語料,LineSentence用於處理分行分詞語料
#sentences1 = word2vec.Text8Corpus(corpus)  #用來處理按文字分詞語料
#print('=--=-=-=-=-=',sentences)
model = word2vec.Word2Vec(sentences, size=12,window=25,min_count=2,workers=5,sg=1,hs=1)  #訓練模型就這一句話  去掉出現頻率小於2的詞
# http://blog.csdn.net/szlcw1/article/details/52751314 訓練skip-gram模型; 第一個引數是訓練預料,min_count是小於該數的單詞會被踢出,預設值為5,size是神經網路的隱藏層單元數,在儲存的model.txt中會顯示size維的向量值。預設是100。預設window=5

第四:儲存模型

# 4儲存模型,以便重用
model.save("test_01.model")   #儲存模型
model.wv.save_word2vec_format('test_01.model.txt','test_01.vocab.txt',binary=False) # 將模型儲存成文字,model.wv.save_word2vec_format()來進行模型的儲存的話,會生成一個模型檔案。裡邊存放著模型中所有詞的詞向量。這個檔案中有多少行模型中就有多少個詞向量。

第五:載入模型,驗證模型

#5詞向量驗證
#載入訓練好的模型
model = word2vec.Word2Vec.load("test_01.model")  #載入訓練好的語料模型
# 計算兩個詞的相似度/相關程度
# role1 = ['大聖','悟空','齊天大聖','師兄','老孫','行者','孫行者','孫悟空']
# role2 = ['天蓬','豬悟能','老豬','八戒','豬八戒','呆子']
role1 = ['天地','萬物','一元']
role2 = ['天地','百歲']
pairs = [(x,y) for x in role1 for y in role2]
print(pairs)  #[('天地', '天地'), ('天地', '百歲'), ('萬物', '天地'), ('萬物', '百歲'), ('一元', '天地'), ('一元', '百歲')]

#pairs = [('觀音','豬悟能'),('觀音','天蓬'),('觀音','八戒'),('呆子','八戒'),('天蓬','嫦娥'),('天蓬','大聖'),('天蓬','捲簾'),('八戒','姐姐')]
for pair in pairs:
    print("> [%s]和[%s]的相似度為:" % (pair[0],pair[1]), model.similarity(pair[0], pair[1]))   # 預測相似性
# 計算某個詞的相關詞列表
figures = ['如來','西天','觀音','老君','師父','老孫','八戒','沙和尚','南天門','王母','天王']
for figure in figures:
    print("> 和[%s]最相關的詞有:\n" % figure, '\n'.join([x[0].ljust(4,' ')+str(x[1]) for x in model.most_similar(figure, topn=10)]),sep='')  # 預設10個最相關  

結果:



參考文章:

http://blog.csdn.net/u014595019/article/details/51884529

scikit-learn文字特徵提取之TfidfVectorizer   :

    http://blog.csdn.net/pipisorry/article/details/41957763

    http://blog.csdn.net/pipisorry/article/details/41957763