中文word vector與分詞
在語言學的定義中,詞(word)是表達意義的最小單位;
字(character)是書寫的最小單位。
一段文字是以「字」為單位組成的。
處理中文需要將「字」分出「詞」,才能以詞為單位使用詞向量。
與之相比,英文的分詞 (或稱斷詞,word segmentation) 是用空白作為分隔。
使用中文詞向量
下載一組中文詞向量
到網站1
https://mega.nz/#!5LwDjZia!f77y-eWm90H3akg8mD9CqhOZ89NihirRKN4IT1SJ01Q
下載中文詞向量資料
使用jieba套件做中文分詞
以下python代碼(在指令行輸入)將安裝jieba。(也許會需要sudo)
pip install jieba # python 2
python3 -m pip install jieba # python 3
以下python代碼將會讀取中文詞向量資料
# -*- coding: utf-8 -*-
import numpy as np # 安裝numpy
dim = 0
word_vecs= {}
# 開啟詞向量檔案
with open('cna.cbow.cwe_p.tar_g.512d.0.txt') as f:
for line in f:
# 假設我們的詞向量有300維
# 由word以及向量中的元素共301個
# 以空格分隔組成詞向量檔案中一行
tokens = line.strip().split()
# 第一行是兩個整數,分別代表有幾個詞向量,以及詞向量維度
if len(tokens) == 2:
dim = int(tokens[1])
continue
word = tokens[0]
vec = np.array([ float(t) for t in tokens[1:] ])
word_vecs[word] = vec
# 之後可以從word_vecs這個dict中取得詞向量
以下python代碼示範使用詞向量平均找出答案句的方法
# -*- coding: utf-8 -*-
import jieba
import numpy as np
# 我們要從answers中挑出應該接在dialogue之後的短句
dialogue = "如果飛機在飛行當中打一個小洞的話 會不會影響飛行的安全呢"
answers = [
"其實狗搖尾巴有很多種方式 高興搖尾巴 生氣也搖尾巴",
"如果這個洞的話經過仔細的設計的話 應該不至於造成太大問題",
"所以只要依照政府規定 在採收前十天不要噴灑農藥",
"靜電才是加油站爆炸的元凶 手機不過是代罪羔羊",
"我們可以用表面張力及附著力的原理 來測試看看",
"不過蝦子死亡後 身體會釋放出有毒素的體液 可能造成水的變質"]
emb_cnt = 0
avg_dlg_emb = np.zeros((dim,))
# jieba.cut 會把dialogue作分詞
# 對於有在word_vecs裡面的詞我們才把它取出
# 最後詞向量加總取平均,作為句子的向量表示
for word in jieba.cut(dialogue):
if word in word_vecs:
avg_dlg_emb += word_vecs[word]
emb_cnt += 1
avg_dlg_emb /= emb_cnt
emb_cnt = 0
max_idx = -1
max_sim = -10
# 在六個回答中,每個答句都取詞向量平均作為向量表示
# 我們選出與dialogue句子向量表示cosine similarity最高的短句
for idx,ans in enumerate(answers):
avg_ans_emb = np.zeros((dim,))
for word in jieba.cut(ans):
if word in word_vecs:
avg_ans_emb += word_vecs[word]
emb_cnt += 1
sim = np.dot(avg_dlg_emb, avg_ans_emb) / np.linalg.norm(avg_dlg_emb) / np.linalg.norm(avg_ans_emb)
print("Ans#%d: %f" % (idx, sim))
if sim > max_sim:
max_idx = idx
max_sim = sim
print("Answer:%d" % max_idx)
除了網站1,還有其他詞向量的下載連結:
cna.cbow.512.0.txt
https://mega.nz/#!sD4DHL7a!zLXxR_IfF_8NcsQFa2UzygEIHgkXcrF-wdylglr9s2I
cna.cbow.cwe_p.512d.0.txt
https://mega.nz/#!9bgV1RAb!8VEaQAEBzZBu7nQyWSQQJTWqW3gQYYxRdE7SIUNbyjg
cna.cbow.cwe_p.tar_g.512d.0.txt
https://mega.nz/#!5LwDjZia!f77y-eWm90H3akg8mD9CqhOZ89NihirRKN4IT1SJ01Q
訓練詞向量
有時用別人的詞向量不見得適合用於自己要處理的問題:例如從新聞文字學來的詞向量,要用在PTT文章分類時,新聞和PTT裡的用詞不太一樣,可能造成模型表現不佳。這時就可以用與手邊問題較相似的語料,重新訓練一組詞向量。
以下說明 word2vec 訓練詞向量的步驟,開發環境是Linux/Mac OSX,並在終端機中執行。
1 先到網站2
https://code.google.com/archive/p/word2vec/source/default/source
下載word2vec, 解壓縮後,移至trunk/ 資料夾裡。
2 在指令行輸入make,編譯程式。編譯程式成功後會產生一個word2vec可執行檔。
3 整理語料。把語料中的每一行文句分詞後,用空白隔開,儲存在一個檔案裡。
假設這個檔案叫做corpus.txt,將語料中的每一行文句用空白隔開分詞的程式碼如下
import jieba
out_f = open("corpus.txt","w")
with open("<your_raw_text>.txt", "r") as f:
for line in f:
word_list = list(jieba.cut(line.strip())
out_f.write("%s\n" % " ".join(word_list))
4 輸入以下的指令進行訓練
./word2vec -train corpus.txt -output my.cbow.200d.txt -size 200 -window 5 -sample 1e-4 -negative 10 -hs 0 -cbow 1 -iter 15 -threads 8 -min-count 5
# -size 詞向量維度
# -cbow 使用CBOW(1)或Skipgram(0)
# -iter 重複訓練的迭代次數
# -thraeds 使用多少個執行緒
# -min-count 捨棄語料中詞頻少於這個值的詞
指令的參數是不錯的參考值,可再自由調整。
最後會產生一個 my.cbow.200d.txt的詞向量檔案。
除了word2vec,還有其他的詞向量訓練套件可供嘗試。
Facebook fasttext
chaaracter-enhanced word embedding (CWE)
Glyph-enhanced word embedding (GWE)
用於訓練中文詞向量的語料(corpus)
[0]
https://fgc.stpi.narl.org.tw/activity/videoDetail/4b1141305ddf5522015de5479f4701b1