使用Gensim模組訓練詞向量

2020-08-17 09:05:42

使用Gensim模組訓練詞向量

如果在以詞爲基本單元輸入的自然語言處理任務中,都避免不了使用詞的表示,詞的表示有很多種,這裏主要介紹的就是詞向量,word2vec是目前比較通用的訓練詞向量的工具,使用Gensim模組,可以使詞向量的訓練變的簡單,那麼我們知道對於word2vec來說,不論的Skip-Gram models還是CBOW models,他們的輸入以及輸出都是以單詞爲基本單位的,只是他們對應的輸入以及輸出不一樣:

1、Skip-Gram models:輸入爲單個詞,輸出目標爲多個上下文單詞;

2、CBOW models:輸入爲多個上下文單詞,輸出目標爲一個單詞;

我們從上面可以看出,無論是Skip-Gram models還是CBOW models基本的單元都是詞,那麼我們獲取到的語料,必須要經過分詞處理以後才能 纔能用於詞向量的訓練語料。

1.數據的處理

這裏我選用維基百科作爲詞向量模型的訓練語料,如果還不知道怎麼去處理維基百科數據,可以參考下面 下麪這篇文章,爲了效率,我選擇了個小的語料,當然對於詞向量的訓練,語料越大訓練出來的結果越好:

得到的中文語料以後,最重要的就是要進行分詞的操作了,這裏使用jieba分詞工具對語料進行精確模式的分詞:

import jieba.analyse
import codecs

#以寫的方式開啓原始的簡體中文語料庫
# 從檔案讀取數據
# f=codecs.open('zhwiki_jian_zh.txt','r',encoding="utf8")
# #將分完詞的語料寫入到wiki_jian_zh_seg-189.5.txt檔案中
# target = codecs.open("wiki_jian_zh_seg-189.5.txt", 'w',encoding="utf8")

f=codecs.open('text.txt','r',encoding="utf8")
# 將分完詞的語料寫入到wiki_jian_zh_seg-189.5.txt檔案中
target = codecs.open("wiki_jian_zh_seg-189.5.txt", 'w',encoding="utf8")
print('open files')
line_num=1
# 一行一行讀取數據
line = f.readline()
open files
#回圈遍歷每一行,並對這一行進行分詞操作
#如果下一行沒有內容的話,就會readline會返回-1,則while -1就會跳出回圈
while line:
    print('---- processing ', line_num, ' article----------------')   
    line_seg = " ".join(jieba.cut(line))
    print(line_seg)
    target.writelines(line_seg)
    line_num = line_num + 1
    line = f.readline()
Building prefix dict from the default dictionary ...


---- processing  1  article----------------


Dumping model to file cache /var/folders/_d/5tm50b5j6x9b5rlhr_20xy_c0000gn/T/jieba.cache
Loading model cost 1.148 seconds.
Prefix dict has been built successfully.


python 的 內部 是 使用 unicode 來 處理 的 , 但是 unicode 的 使用 需要 考慮 的 是 它 的 編碼 格式 有 兩種 , 一是 UCS - 2 , 它 一共 有 65536 個碼   位 , 另 一種 是 UCS - 4 , 它 有 2147483648g 個 碼位 。 對於 這 兩種 格式 , python 都 是 支援 的 , 這個 是 在 編譯 時 通過 -- enable -   unicode = ucs2 或 -- enable - unicode = ucs4 來 指定 的 。 那麼 我們 自己 預設 安裝 的 python 有 的 什麼 編碼 怎麼 來 確定 呢 ? 有 一個   辦法 , 就是 通過 sys . maxunicode 的 值來 判斷 : 

---- processing  2  article----------------
python 的 內部 是 使用 unicode 來 處理 的 , 但是 unicode 的 使用 需要 考慮 的 是 它 的 編碼 格式 有 兩種 , 一是 UCS - 2 , 它 一共 有 65536 個碼   位 , 另 一種 是 UCS - 4 , 它 有 2147483648g 個 碼位 。 對於 這 兩種 格式 , python 都 是 支援 的 , 這個 是 在 編譯 時 通過 -- enable -   unicode = ucs2 或 -- enable - unicode = ucs4 來 指定 的 。 那麼 我們 自己 預設 安裝 的 python 有 的 什麼 編碼 怎麼 來 確定 呢 ? 有 一個   辦法 , 就是 通過 sys . maxunicode 的 值來 判斷 :
#關閉兩個檔案流,並退出程式
f.close()
target.close()
# exit()

2.訓練模型

有了分好詞的語料,我們就可以通過Gensim模組中的word2vec函數來訓練語料。

import logging
import os.path
import sys
import multiprocessing
from gensim.models import Word2Vec
from gensim.models.word2vec import LineSentence
#程式的入口
#1.如果當前指令碼檔案做模組供其他程式使用的話,不會執行if __name__ == '__main__':中的內容
#2.如果直接執行當前的額指令碼檔案的話,執行if __name__ == '__main__':中的內容
if __name__ == '__main__':
    #1.os.path.basename('g://tf/code') ==>code
    #2.sys.argv[0]獲取的是指令碼檔案的檔名稱
#     os.path.basename(path) 返迴檔名
    program = os.path.basename(sys.argv[0])
    
    #指定name,返回一個名稱爲name的Logger範例
    logger = logging.getLogger(program)
    
    #1.format: 指定輸出的格式和內容,format可以輸出很多有用資訊,
    #%(asctime)s: 列印日誌的時間
    #%(levelname)s: 列印日誌級別名稱
    #%(message)s: 列印日誌資訊
    logging.basicConfig(format='%(asctime)s: %(levelname)s: %(message)s')
    logging.root.setLevel(level=logging.INFO)
    #列印這是一個通知日誌
    logger.info("running %s" % ' '.join(sys.argv))
    # check and process input arguments
    if len(sys.argv) < 4:
        print (globals()['__doc__'] % locals())
        sys.exit(1)
    #inp:分好詞的文字
    #outp1:訓練好的模型
    #outp2:得到的詞向量
    inp, outp1, outp2 = sys.argv[1:4]
    '''
    LineSentence(inp):格式簡單:一句話=一行; 單詞已經過預處理並被空格分隔。
    size:是每個詞的向量維度; 
    window:是詞向量訓練時的上下文掃描視窗大小,視窗爲5就是考慮前5個詞和後5個詞; 
    min-count:設定最低頻率,預設是5,如果一個詞語在文件中出現的次數小於5,那麼就會丟棄; 
    workers:是訓練的進程數(需要更精準的解釋,請指正),預設是當前執行機器的處理器核數。這些參數先記住就可以了。
    sg ({0, 1}, optional) – 模型的訓練演算法: 1: skip-gram; 0: CBOW
    alpha (float, optional) – 初始學習率
    iter (int, optional) – 迭代次數,預設爲5
    '''
    model = Word2Vec(LineSentence(inp), size=400, window=5, min_count=5, workers=multiprocessing.cpu_count())
    model.save(outp1)
    #不以C語言可以解析的形式儲存詞向量
    model.wv.save_word2vec_format(outp2, binary=False)

3.測試模型

有了詞向量我們就可以使用詞向量來做一些自然語言處理的任務了。那在這之前,我們需要測試一個模型是否訓練成功。

from gensim.models import Word2Vec

en_wiki_word2vec_model = Word2Vec.load('wiki_zh_jian_text.model')

testwords = ['金融','上','股票','跌','經濟']
for i in range(5):
    res = en_wiki_word2vec_model.most_similar(testwords[i])
    print (testwords[i])
    print (res)

‘’’
result:
金融
[(‘金融業’, 0.7712020874023438), (‘房地產’, 0.7530461549758911), (‘銀行業’, 0.7478024959564209), (‘保險業’, 0.7240537405014038), (‘金融機構’, 0.7114974856376648), (‘投資銀行’, 0.7104595899581909), (‘證券’, 0.7046274542808533), (‘信貸’, 0.7021963596343994), (‘金融服務’, 0.6956385374069214), (‘公共事業’, 0.6882480382919312)]

[(‘之上’, 0.5678470134735107), (‘上以’, 0.4623713493347168), (‘上面’, 0.4558977782726288), (‘上用’, 0.42831096053123474), (‘水性’, 0.4084252119064331), (‘上會’, 0.3999699354171753), (‘方面’, 0.3975197672843933), (‘上要’, 0.3963406980037689), (‘上僅’, 0.3950901925563812), (‘面上’, 0.38935011625289917)]
股票
[(‘期貨’, 0.7636638879776001), (‘債券’, 0.7634198069572449), (‘外匯’, 0.7477541565895081), (‘獲利’, 0.7359930276870728), (‘期權’, 0.7332447171211243), (‘A股’, 0.7319167852401733), (‘存款’, 0.7306094765663147), (‘普通股’, 0.7264690399169922), (‘不動產’, 0.724310040473938), (‘證券’, 0.7240179777145386)]

[(‘滑落’, 0.70113605260849), (‘回落’, 0.6962391138076782), (‘漲’, 0.6842378377914429), (‘季尾’, 0.6791133284568787), (‘攀升’, 0.6673789620399475), (‘急跌’, 0.6652034521102905), (‘跌落’, 0.6540493965148926), (‘飆升’, 0.6493663787841797), (‘下跌’, 0.6452913284301758), (‘回升’, 0.6349585652351379)]
經濟
[(‘工商業’, 0.631495475769043), (‘國民經濟’, 0.6289297342300415), (‘農業’, 0.6132777333259583), (‘生產力’, 0.6094485521316528), (‘金融’, 0.5886996984481812), (‘市場經濟’, 0.5880722403526306), (‘旅遊業’, 0.585972011089325), (‘對外貿易’, 0.575571596622467), (‘經濟繁榮’, 0.5738641023635864), (‘金融業’, 0.5717495083808899)]
‘’’