自然语言处理库——Gensim之Word2vec
? ? ? ? Gensim(http://pypi.python.org/pypi/gensim)是一款開源的第三方Python工具包,用于從原始的非結構化的文本中,無監督地學習到文本隱層的主題向量表達。 主要用于主題建模和文檔相似性處理,它支持包括TF-IDF,LSA,LDA,和word2vec在內的多種主題模型算法。Gensim在諸如獲取單詞的詞向量等任務中非常有用。
1. gensim概述
使用Gensim訓練Word2vec十分方便,訓練步驟如下:
? ? ? ? 1)將語料庫預處理:一行一個文檔或句子,將文檔或句子分詞(以空格分割,英文可以不用分詞,英文單詞之間已經由空格分割,中文預料需要使用分詞工具進行分詞,常見的分詞工具有StandNLP、ICTCLAS、Ansj、FudanNLP、HanLP、結巴分詞等);
? ? ? ? 2)將原始的訓練語料轉化成一個sentence的迭代器,每一次迭代返回的sentence是一個word(utf8格式)的列表。可以使用Gensim中word2vec.py中的LineSentence()方法實現;
? ? ? ? 3)將上面處理的結果輸入Gensim內建的word2vec對象進行訓練即可:
from gensim.models import Word2Vec sentences = word2vec.LineSentence('./in_the_name_of_people_segment.txt') # in_the_name_of_people_segment.txt 分詞之后的文檔model = Word2Vec(sentences , size=100, window=5, min_count=1, workers=4)2. gensim word2vec API概述:
? ? ? ? 在gensim中,word2vec 相關的API都在包gensim.models.word2vec中。和算法有關的參數都在類gensim.models.word2vec. Word2Vec中。算法需要注意的參數有:
class Word2Vec(utils.SaveLoad):def __init__(self, sentences=None, size=100, alpha=0.025, window=5, min_count=5,max_vocab_size=None, sample=1e-3, seed=1, workers=3, min_alpha=0.0001,sg=0, hs=0, negative=5, cbow_mean=1, hashfxn=hash, iter=5, null_word=0,trim_rule=None, sorted_vocab=1, batch_words=MAX_WORDS_IN_BATCH):- sentences:可以是一個list,對于大語料集,建議使用BrownCorpus,Text8Corpus或lineSentence構建。
- size:是指詞向量的維度,默認為100。這個維度的取值一般與我們的語料的大小相關,如果是不大的語料,比如小于100M的文本語料,則使用默認值一般就可以了。如果是超大的語料,建議增大維度。大的size需要更多的訓練數據,但是效果會更好. 推薦值為幾十到幾百。
- window:窗口大小,即詞向量上下文最大距離,這個參數在我們的算法原理篇中標記為c。window越大,則和某一詞較遠的詞也會產生上下文關系。默認值為5。在實際使用中,可以根據實際的需求來動態調整這個window的大小。如果是小語料則這個值可以設的更小。對于一般的語料這個值推薦在[5,10]之間。個人理解應該是某一個中心詞可能與前后多個詞相關,也有的詞在一句話中可能只與少量詞相關(如短文本可能只與其緊鄰詞相關)。
- min_count: 需要計算詞向量的最小詞頻。這個值可以去掉一些很生僻的低頻詞,默認是5。如果是小語料,可以調低這個值。可以對字典做截斷, 詞頻少于min_count次數的單詞會被丟棄掉。
- negative:即使用Negative Sampling時負采樣的個數,默認是5。推薦在[3,10]之間。這個參數在我們的算法原理篇中標記為neg。
- cbow_mean: 僅用于CBOW在做投影的時候,為0,則算法中的為上下文的詞向量之和,為1則為上下文的詞向量的平均值。在我們的原理篇中,是按照詞向量的平均值來描述的。個人比較喜歡用平均值來表示,默認值也是1,不推薦修改默認值。
- ?iter: 隨機梯度下降法中迭代的最大次數,默認是5。對于大語料,可以增大這個值。
- alpha: 是初始的學習速率,在訓練過程中會線性地遞減到min_alpha。在隨機梯度下降法中迭代的初始步長。算法原理篇中標記為η,默認是0.025。
- min_alpha: 由于算法支持在迭代的過程中逐漸減小步長,min_alpha給出了最小的迭代步長值。隨機梯度下降中每輪的迭代步長可以由iter,alpha,?min_alpha一起得出。這部分由于不是word2vec算法的核心內容,因此在原理篇我們沒有提到。對于大語料,需要對alpha,?min_alpha,iter一起調參,來選擇合適的三個值。
- max_vocab_size: 設置詞向量構建期間的RAM限制,設置成None則沒有限制。
- sample: 高頻詞匯的隨機降采樣的配置閾值,默認為1e-3,范圍是(0,1e-5)。
- seed:用于隨機數發生器。與初始化詞向量有關。
- workers:用于控制訓練的并行數。
3. gensim ?word2vec實戰
3.1 例子1
import os import numpy as np import nltk import datetime as dt from keras.models import Sequential, load_model from keras.layers import Dense from keras.layers import Dropout from keras.layers import LSTM from gensim.models import Word2Vec# 1.文本讀入 # (1)加載文本 raw_text = '' # os.listdir()方法用于返回指定的文件夾包含的文件或文件夾的名字的列表 for file in os.listdir('./input/'): if file.endswith(".txt"):raw_text += open("./input/" + file, errors='ignore').read() + '\n\n' raw_text = raw_text.lower()# (2)加載punkt句子分割器 sentensor = nltk.data.load('tokenizers/punkt/english.pickle') # <nltk.tokenize.punkt.PunktSentenceTokenizer at 0x16cc42020f0># (3)對句子進行分割:將文章分割為句子列表 sents = sentensor.tokenize(raw_text) # 句子列表['句子1.','句子2.'...] corpus = []# (4)分詞word tokenize:將句子分割為單詞列表 for sen in sents:corpus.append(nltk.word_tokenize(sen)) # 單詞列表[['sexes', 'similar', '.'],['family', 'hirundinidae', '.'],...]# 2.構建詞向量:W2V w2v_model = Word2Vec(corpus, size=128, window=5, min_count=3, workers=4) # 128維的詞向量# 3. 處理我們的training data,把源數據變成一個長長的x,好讓LSTM學會predict下一個單詞 raw_input = [item for sublist in corpus for item in sublist] # 將corpus的二維變為一維['sexes', 'similar', '.','family', 'hirundinidae', '.',...]text_stream = []vocab = w2v_model.wv.vocab # 字典dict:獲取詞向量中每個單詞'''{'project': <gensim.models.keyedvectors.Vocab at 0x1be2f656048>,'gutenberg': <gensim.models.keyedvectors.Vocab at 0x1be2f656080>,"'s": <gensim.models.keyedvectors.Vocab at 0x1be2f6560b8>,...}'''# 將raw_input中在w2v_model詞向量中的單詞添加到text_stream for word in raw_input:if word in vocab:text_stream.append(word) # 4. 構造訓練測試集:窗口化,處理成LSTM的輸入格式 seq_length = 10 x = [] y = [] for i in range(0, len(text_stream) - seq_length):given = text_stream[i:i + seq_length]predict = text_stream[i + seq_length]x.append(np.array([w2v_model[word] for word in given])) # 將每個單詞轉換為詞向量 y.append(w2v_model[predict])# len(w2v_model[given[0]])=128 w2v_model[word]為word對應的詞向量# 5. ①將input的數字表達(w2v),變成LSTM需要的數組格式: [樣本數,時間步伐,特征], # ②對于output,我們直接用128維的輸出 x = np.reshape(x, (-1, seq_length, 128)) y = np.reshape(y, (-1, 128))# 6. LSTM模型構建 model = Sequential() model.add(LSTM(256, dropout_W=0.2, dropout_U=0.2, input_shape=(seq_length,128))) model.add(Dropout(0.2)) model.add(Dense(128, activation='sigmoid')) model.compile(loss='mse', optimizer='adam')# 7.跑模型 model.fit(x, y, nb_epoch=30, batch_size=2048) save_fname = os.path.join('./', '%s-e%s-3.h5' % (dt.datetime.now().strftime('%Y%m%d-%H%M%S'),str(50))) model.save(save_fname)# 8. 測試 # ① def predict_next(input_array):x = np.reshape(input_array, (-1, seq_length, 128))y = model.predict(x)return ydef string_to_index(raw_input):raw_input = raw_input.lower()input_stream = nltk.word_tokenize(raw_input)res = []for word in input_stream[(len(input_stream)-seq_length):]:res.append(w2v_model[word])return resdef y_to_word(y):word = w2v_model.most_similar(positive=y, topn=1) # 獲取單個詞相關的前n個詞語return word # ② def generate_article(init, rounds=30):in_string = init.lower()for i in range(rounds):n = y_to_word(predict_next(string_to_index(in_string)))in_string += ' ' + n[0][0]# print('n[0]:', n[0]) = ('curiosity', 0.7301754951477051)print('n[0][0]:', n[0][0])return in_string# ③ # init = 'Language Models allow us to measure how likely is, which is an important for Machine' init1 = 'As I went in to see the famous Booth Collection, a thought of the bird I have just described came into my' article1 = generate_article(init1)?word2Vec 獲取訓練好后所有的詞:
? ? ? 在gensim 1.0.0 以前的版本可以使用:model.vocab
? ? ?在 gensim 1.0以后的版本使用:model.wv.vocab
3.2 例子2
? ? ? ? 選擇的《人民的名義》的小說原文作為語料,語料原文在這里。
完整代碼參見:github:?https://github.com/ljpzzz/machinelearning/blob/master/natural-language-processing/word2vec.ipynb
拿到了原文,我們首先要進行分詞,這里使用結巴分詞完成。在中文文本挖掘預處理流程總結中,我們已經對分詞的原理和實踐做了總結。因此,這里直接給出分詞的代碼,分詞的結果,我們放到另一個文件中。代碼如下, 加入下面的一串人名是為了結巴分詞能更準確的把人名分出來。
# -*- coding: utf-8 -*-import jieba import jieba.analysejieba.suggest_freq('沙瑞金', True) jieba.suggest_freq('田國富', True) jieba.suggest_freq('高育良', True) jieba.suggest_freq('侯亮平', True) jieba.suggest_freq('鐘小艾', True) jieba.suggest_freq('陳巖石', True) jieba.suggest_freq('歐陽菁', True) jieba.suggest_freq('易學習', True) jieba.suggest_freq('王大路', True) jieba.suggest_freq('蔡成功', True) jieba.suggest_freq('孫連城', True) jieba.suggest_freq('季昌明', True) jieba.suggest_freq('丁義珍', True) jieba.suggest_freq('鄭西坡', True) jieba.suggest_freq('趙東來', True) jieba.suggest_freq('高小琴', True) jieba.suggest_freq('趙瑞龍', True) jieba.suggest_freq('林華華', True) jieba.suggest_freq('陸亦可', True) jieba.suggest_freq('劉新建', True) jieba.suggest_freq('劉慶祝', True)with open('./in_the_name_of_people.txt') as f:document = f.read()#document_decode = document.decode('GBK')document_cut = jieba.cut(document)#print ' '.join(jieba_cut) //如果打印結果,則分詞效果消失,后面的result無法顯示result = ' '.join(document_cut)result = result.encode('utf-8')with open('./in_the_name_of_people_segment.txt', 'w') as f2:f2.write(result)? ? ? ? 拿到了分詞后的文件,在一般的NLP處理中,會需要去停用詞。由于word2vec的算法依賴于上下文,而上下文有可能就是停詞。因此對于word2vec,我們可以不用去停詞。
現在我們可以直接讀分詞后的文件到內存。這里使用了word2vec提供的LineSentence類來讀文件,然后套用word2vec的模型。這里只是一個示例,因此省去了調參的步驟,實際使用的時候,你可能需要對我們上面提到一些參數進行調參。
# import modules & set up logging import logging import os from gensim.models import word2veclogging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)sentences = word2vec.LineSentence('./in_the_name_of_people_segment.txt') model = word2vec.Word2Vec(sentences, hs=1,min_count=1,window=3,size=100)模型出來了,我們可以用來做什么呢?這里給出三個常用的應用。
1.? 第一個是最常用的:找出某一個詞向量最相近的詞集合
代碼如下:
req_count = 5 for key in model.wv.similar_by_word('沙瑞金'.decode('utf-8'), topn =100):if len(key[0])==3:req_count -= 1print key[0], key[1]if req_count == 0:break;我們看看沙書記最相近的一些3個字的詞(主要是人名)如下:
高育良 0.967257142067 李達康 0.959131598473 田國富 0.953414440155 易學習 0.943500876427 祁同偉 0.9429329633712. 第二個應用:看兩個詞向量的相近程度
這里給出了書中兩組人的相似程度:
print model.wv.similarity('沙瑞金'.decode('utf-8'), '高育良'.decode('utf-8')) print model.wv.similarity('李達康'.decode('utf-8'), '王大路'.decode('utf-8'))輸出如下:
0.961137455325 0.9355893657063. 第三個應用:找出不同類的詞
這里給出了人物分類題:
print model.wv.doesnt_match(u"沙瑞金 高育良 李達康 劉慶祝".split()) word2vec也完成的很好,輸出為"劉慶祝"。以上就是用gensim學習word2vec實戰的所有內容。
?
參考:
https://blog.csdn.net/sinat_26917383/article/details/69803018#800_420
總結
以上是生活随笔為你收集整理的自然语言处理库——Gensim之Word2vec的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Attention的本质:从Encode
- 下一篇: 自然语言处理库——NLTK