word2vec實戰:獲取和預處理中文維基百科(Wikipedia)語料庫,並訓練成word2vec模型
前言
傳統的方法是將詞彙作為離散的單一符號,這些符號編碼毫無規則,無法提供詞彙之間可能存在的關聯關係,而詞彙的向量表示將克服上述難題。
向量空間模型(VSM)將詞彙表示在一個連續的向量空間中,語義近似的詞被對映為相鄰的資料點。VSM依賴於分散式假設思想,該思想的核心是:出現於相同的上下文情景中的詞彙都有相似的語義。
基於VSM假設有2種研究方法:
1,基於計數的方法:計算某詞彙極其臨近詞在一個大型語料庫中共同出現的頻率,然後將其對映到一個小而稠密的向量中。
2,預測方法:該方法試圖直接從某詞彙的臨近詞對其進行預測,此過程利用學習到的向量。
word2vec是一種可以進行高效率詞巢狀學習的預測模型,該模型有2種具體的形式:
1,CBOW模型:根據上下文詞彙“the cat sits on the”,來預測目標詞“mat”。
2,skip-gram模型:通過目標詞來預測源詞彙。
本文不關注具體理論,而是詳細介紹如何獲取並預處理中文維基百科語料庫,並訓練成word2vec模型。
實驗環境:Ubuntu14.04/Python2.7(Anaconda版)
正文
下載的檔案是一個大小為1.3G的壓縮包,解壓後是個5.8G左右的xml檔案,內容是網頁標籤形式的。我們需要抽取出其中的有效資訊。
2,使用Wikipedia Extractor抽取正文
Wikipedia Extractor是義大利人用Python寫的一個維基百科抽取器,使用非常方便。下載之後直接使用這條命令即可完成抽取,執行時間很快。執行以下命令。
$ sudo apt-get install unzip python python-dev python-pip
$ git clone https://github.com/attardi/wikiextractor.git wikiextractor
$ cd wikiextractor
$ sudo python setup.py install
$ ./WikiExtractor.py -b 1024M -o extracted zhwiki-latest-pages-articles.xml.bz2
引數-b 1024M表示以1024M為單位切分檔案,預設是1M。由於最後生成的正文文字約1060M,把引數設定的大一些可以保證最後的抽取結果全部存在一個檔案裡。這裡我們設為1024M,可以分成一個1G的大檔案和一個36M的小檔案,後續的步驟可以先在小檔案上實驗,再應用到大檔案上。
這裡,我們得到了2個文字檔案:wiki_00, wiki_01。大小分別為:1024M, 36.7M。
3,繁體轉簡體
維基百科的中文資料是繁簡混雜的,裡面包含大陸簡體、臺灣繁體、港澳繁體等多種不同的資料。有時候在一篇文章的不同段落間也會使用不同的繁簡字。
為了處理方便起見,我們直接使用了開源專案opencc。參照安裝說明的方法,安裝完成之後,使用下面的命令進行繁簡轉換,整個過程也很快:
$ sudo apt-get install opencc
$ opencc -i wiki_00 -o zh_wiki_00 -c zht2zhs.ini
$ opencc -i wiki_01 -o zh_wiki_01 -c zht2zhs.ini
命令中的wiki_00/wiki_01這個檔案是此前使用Wikipedia Extractor得到的。到了這裡,我們已經完成了大部分繁簡轉換工作。
這裡,我們得到了2個簡體檔案:zh_wiki_00,zh_wiki_01。大小分別為:1024M,36.7M。同上步結果大小不變。
4,符號處理
由於Wikipedia Extractor抽取正文時,會將有特殊標記的外文直接剔除。我們最後再將「」『』這些符號替換成引號,順便刪除空括號,就大功告成了!程式碼如下:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import re
import sys
import codecs
def myfun(input_file):
p1 = re.compile(ur'-\{.*?(zh-hans|zh-cn):([^;]*?)(;.*?)?\}-')
p2 = re.compile(ur'[(\(][,;。?!\s]*[)\)]')
p3 = re.compile(ur'[「『]')
p4 = re.compile(ur'[」』]')
outfile = codecs.open('std_' + input_file, 'w', 'utf-8')
with codecs.open(input_file, 'r', 'utf-8') as myfile:
for line in myfile:
line = p1.sub(ur'\2', line)
line = p2.sub(ur'', line)
line = p3.sub(ur'“', line)
line = p4.sub(ur'”', line)
outfile.write(line)
outfile.close()
if __name__ == '__main__':
if len(sys.argv) != 2:
print "Usage: python script.py inputfile"
sys.exit()
reload(sys)
sys.setdefaultencoding('utf-8')
input_file = sys.argv[1]
myfun(input_file)
將上述程式碼儲存到exec.py檔案,並將該檔案放到與資料檔案相同的目錄,執行命令:
$ python exec.py zh_wiki_00
$ python exec.py zh_wiki_01
這裡,我們又得到2個格式化檔案:std_zh_wiki_00,std_zh_wiki_01。大小分別為:1021M,36.6M。大小比之前的檔案要小,因為修改刪除了檔案中的符號。
安裝很簡單:$ pip install jieba
安裝好後執行命令進行分詞:
python -m jieba -d " " ./std_zh_wiki_00 > ./cut_std_zh_wiki_00
python -m jieba -d " " ./std_zh_wiki_01 > ./cut_std_zh_wiki_01
命令中的-d ” “選項,雙引號中是一個空格,指的是以空格分割詞彙。
這裡,我們又得到2個分詞檔案:cut_std_zh_wiki_00,cut_std_zh_wiki_01。大小分別為:1.21G,44.6M。比之前的檔案要大,因為檔案中加入了很多空格符。
6,訓練word2vec模型
訓練模型我們使用python的gensim庫提供的方法,gensim官網。
安裝非常簡單:$ pip install gensim
接下來,我們用1.21G的大檔案進行訓練,訓練程式碼也很簡單:
from gensim.models import word2vec
import logging
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
sentences = word2vec.LineSentence(u'./cut_std_zh_wiki_00')
model = word2vec.Word2Vec(sentences,size=200,window=5,min_count=5,workers=4)
model.save('./word2vecModel/WikiCHModel')
訓練的過程進度會列印在控制檯。訓練結束後我們就得到了一個word2vec模型。
7,呼叫並測試word2vec模型
呼叫模型也很簡單,同樣使用gensim庫。
from gensim.models import word2vec
model = word2vec.Word2Vec.load('./word2vecModel/WikiCHModel')
print(model.wv.similarity('奧運會','金牌')) #兩個詞的相關性
print(model.wv.most_similar(['倫敦','中國'],['北京'])) # 北京is to中國 as 倫敦is to?