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函式的各個引數可以參考:
- logging.basicConfig函式各引數:
- filename: 指定日誌檔名
- filemode: 和file函式意義相同,指定日誌檔案的開啟模式,'w'或'a'
- format: 指定輸出的格式和內容,format可以輸出很多有用資訊,如上例所示:
- %(levelno)s: 列印日誌級別的數值
- %(levelname)s: 列印日誌級別名稱
- %(pathname)s: 列印當前執行程式的路徑,其實就是sys.argv[0]
- %(filename)s: 列印當前執行程式名
- %(funcName)s: 列印日誌的當前函式
- %(lineno)d: 列印日誌的當前行號
- %(asctime)s: 列印日誌的時間
- %(thread)d: 列印執行緒ID
- %(threadName)s: 列印執行緒名稱
- %(process)d: 列印程序ID
- %(message)s: 列印日誌資訊
- datefmt: 指定時間格式,同time.strftime()
- level: 設定日誌級別,預設為logging.WARNING
- 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