中文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

results matching ""

    No results matching ""