【pythonで自然言語処理】word2vecで分散表現した単語を2次元に可視化する

  • 2020年3月20日
  • 2023年11月16日
  • Python
  • 5493view

意味的に近い単語の分布を知りたい。そんなときは、2次元の分布図を作成するのが有効です。

kaggleで特徴量を調査するときにも役立つツールになります。

この記事では、word2vecによる分散表現、PCA(主成分分析)による次元圧縮(N次元から2次元へ)、単語を2次元の図にプロットする方法を解説します。

なお、word2vecによる分散表現についてはUdemyの自然言語処理の講座が参考になります。

この記事のword2vecの部分は、Udemyの自然言語処理の講座を参考にしています。

サイバーセール中はUdemyコースが最大90%OFF▼

世界一コスパが安い!
Udemyはこちらから

実装例をもとに分散表現から2次元にプロットまで解説

処理の流れ

処理の流れは以下の通りになります。

  1. 分布図の作成に必要な文章が入ったファイルを読み込む
  2. 文章ごとに単語を空白で分割する(日本語の場合は形態素分析して分割する)
  3. gensimのword2vecを使って分散表現(N次元の配列)にする
  4. 分散表現により、意味的に近い単語がわかるようになる
  5. PCA(主成分分析)を用いてN次元の分散表現を2次元に圧縮する
  6. 圧縮した分散表現を使って2次元のグラフにプロットする

 

ここからは、ここの項目について解説します。

全体的なコードは、記事の後半に記載しています。

 

単語の分布図の作成に必要な文章が入ったファイルを読み込む

単語の分布図の元になる文章をファイルから読み込みます。

#  テキストファイルの読み込み(なお、前処理は考慮していない)
#  この例では、kaggleにある英語のデータで試しています。
with open("kaggle_dis.txt", mode="r", encoding="utf-8") as f:  
    wagahai = f.read()

 

文章は、kaggleのコンペの英文をtxtファイルに入れています。

文章ごとに単語を空白で分割する

文章の区切りを指定するセパレーターを定義します。

今回は英文のため、セパレーターは改行コードにしています。

日本語の場合は、「。」をセパレータに設定することが多いです。

seperator = "\n"  # このサンプルは、改行で文章を区切っているのでセパレータを改行コードにした。日本語だと「。」にすることが多い
wagahai_list = wagahai.split(seperator)  # セパレーターを使って文章をリストに分割する

wagahai_words = []
for sentence in wagahai_list:
    data = sentence.split() #英語のため空白で分割する。日本語の場合は、形態素の分けます。
    wagahai_words.append(data)   # 文章ごとに単語に分割し、リストに格納
    #wagahai_words.append(t.tokenize(sentence, wakati=True))  日本語の場合はコチラ
    

 

gensimのword2vecを使って分散表現(N次元の配列)にする

word2vecを使って分散表現することにより、意味的に近い単語がわかるようになる。

分散表現はN次元の配列の実数値になります。

 

# size : 中間層のニューロン数・数値に応じて配列の大きさが変わる。数値が多いほど精度が良くなりやすいが、処理が重くなる。
# min_count : この値以下の出現回数の単語を無視
# window : 対象単語を中心とした前後の単語数
# iter : epochs数
# sg : skip-gramを使うかどうか 0:CBOW 1:skip-gram
model = word2vec.Word2Vec(wagahai_words,
                          size=200,
                          min_count=5,
                          window=5,
                          iter=20,
                          sg = 0)

#学習結果を確認します
print(model.wv.vectors.shape)  # 分散表現の形状 Word2Vecのsizeの設定が反映されているのがわかります
print(model.wv.vectors)  #実際の分散表現、size次元の配列になっていることがわかるかと思います。

#類似している(ベクトルの距離的に近い)単語を出力してみる
#以下の例では単語「earthquake」に近い単語を出力することができます。
print(model.most_similar(positive=['earthquake'], topn=20))


 

PCA(主成分分析)を用いてN次元の分散表現を2次元に圧縮する

現時点では、N次元(今回の例では200次元)の配列データになっているため、2次元の図にプロットするためには、2次元まで圧縮する必要があります。

圧縮する方法の一つが主成分分析です。

 


#プロットしたい単語を設定する
#以下の例は、fire,earthquakeなどを設定しています。
words = []
words.append(["fire","r"])
words.append(["earthquake","r"])
words.append(["accident","r"])
length = len(words)
data = []
 
j = 0
while j < length:
    data.append(model[words[j][0]])
    j += 1
    

#主成分分析により2次元に圧縮する
pca = PCA(n_components=2)
pca.fit(data)
data_pca= pca.transform(data)

 

圧縮した分散表現を使って2次元のグラフにプロットする

 

主成分分析により2次元まで次元を圧縮しました。2次元になったところで、

matplotlibで表にプロットします。

 

fig=plt.figure(figsize=(20,12),facecolor='w')

plt.rcParams["font.size"] = 10
i = 0
while i < length_data:
    #点プロット
    plt.plot(data_pca[i][0], data_pca[i][1], ms=5.0, zorder=2, marker="x", color=words[i][1])
 
    #文字プロット
    plt.annotate(words[i][0], (data_pca[i][0], data_pca[i][1]), size=12)
 
    i += 1

plt.show()

実際にプロットすると以下のような2次元の分布図が作成されます。

 

その結果、「was」「or」「a」「is」などのSTOP WORDに設定されやすい単語、「Fire」「accident」などの災害を連想させる単語が集結しているように見えます。

全体的なコード

これまで実装方法を部分的なコードで解説しましたが、全体的なコードを掲載します。

#!/usr/bin/env python
# coding: utf-8

# # word2vecによる分散表現と2次元グラフに単語のプロットする
# 
# ・word2vecによる分散表現に変換する
# ・分散表現をした単語をPCAを使って2次元に圧縮する
# ・圧縮した分散表現を2次元の図にプロットする
# ・参考にした参考動画(Udemy自然言語処理とチャットボット: AIによる文章生成と会話エンジン開発講座より「word2vecによる分散表現」)
# https://www.udemy.com/course/ai-nlp-bot/?deal_code=JPA8DEAL2PERCENTAGE&aEightID=s00000016735001
# 

# ## コーパスの前処理
# ・ファイルから文章データを取り出す
# ・文章ごとに単語に分割する

# In[1]:


import re
import pickle
from janome.tokenizer import Tokenizer
import warnings
warnings.simplefilter('ignore')

#  テキストファイルの読み込み(なお、前処理は考慮していない)
#  この例では、kaggleにある英語のデータで試しています。
with open("kaggle_dis.txt", mode="r", encoding="utf-8") as f:  
    wagahai = f.read()


seperator = "\n"  # このサンプルは、改行で文章を区切っているのでセパレータを改行コードにした。日本語だと「。」にすることが多い
wagahai_list = wagahai.split(seperator)  # セパレーターを使って文章をリストに分割する
#wagahai_list.pop() # 最後の要素は空の文字列になるので、削除
#wagahai_list = [x+seperator for x in wagahai_list]  # 文章の最後に。を追加
        
t = Tokenizer()


wagahai_words = []
for sentence in wagahai_list:
    data = sentence.split() #英語のため空白で分割する。日本語の場合は、形態素の分けます。
    wagahai_words.append(data)   # 文章ごとに単語に分割し、リストに格納
    #wagahai_words.append(t.tokenize(sentence, wakati=True))  日本語の場合はコチラ
    
#ここで、pickleに保存します。
with open('wagahai_words.pickle', mode='wb') as f:  # pickleに保存
    pickle.dump(wagahai_words, f)


# ## gensimのword2vecを用いた学習をする
# 今回はword2vecのためにライブラリgensimを使います。  
# 
# gensimについては、以下を参照 
# https://radimrehurek.com/gensim/
# 
# 以下では、word2vecを用いてコーパスの学習を行い、学習済みのモデルを作成します。

# In[2]:


from gensim.models import word2vec

with open('wagahai_words.pickle', mode='rb') as f:
    wagahai_words = pickle.load(f)
    
    
# size : 中間層のニューロン数・数値に応じて配列の大きさが変わる。数値が多いほど精度が良くなりやすいが、処理が重くなる。
# min_count : この値以下の出現回数の単語を無視
# window : 対象単語を中心とした前後の単語数
# iter : epochs数
# sg : skip-gramを使うかどうか 0:CBOW 1:skip-gram
model = word2vec.Word2Vec(wagahai_words,
                          size=200,
                          min_count=5,
                          window=5,
                          iter=20,
                          sg = 0)


# In[3]:


#学習結果を確認します
print(model.wv.vectors.shape)  # 分散表現の形状 Word2Vecのsizeの設定が反映されているのがわかります
print(model.wv.vectors)  #実際の分散表現、size次元の配列になっていることがわかるかと思います。


# In[4]:


print(len(model.wv.index2word))  # 語彙の数
print(model.wv.index2word[:10])  # 最初の10単語を表示します。頻出単語の順番で出力されるようです。


# In[5]:


#print(model.wv.vectors[0])  # 最初のベクトル
#print(model.wv.__getitem__("maskhttp"))  # 最初の単語「の」のベクトル


# In[6]:


#類似している(ベクトルの距離的に近い)単語を出力してみる
model.most_similar(positive=['earthquake'], topn=20)


# ## 単語を2次元の図にプロットします
# ・PCAを用いてN次元の分散表現を2次元に圧縮する
# ・2次元に圧縮した分散表現を2次元の図にプロットします

# In[8]:


import matplotlib.pyplot as plt
from sklearn.decomposition import PCA

#プロットしたい単語を設定する
#FIreなどの災害の意味で使われそうなものを設定
words = []
words.append(["fire","r"])
words.append(["earthquake","r"])
words.append(["accident","r"])
words.append(["involving","r"])
words.append(["Hawaii","r"])
words.append(["Africa","c"])
words.append(["San","c"])
words.append(["Francisco","c"])
words.append(["maskusername","c"])

#頻出単語もセットする
print(model.wv.index2word[:50])
for s in model.wv.index2word[:50]:
    words.append([s,"b"])


length = len(words)
data = []
 
j = 0
while j < length:
    data.append(model[words[j][0]])
    j += 1
    

#主成分分析により2次元に圧縮する
pca = PCA(n_components=2)
pca.fit(data)
data_pca= pca.transform(data)
 
length_data = len(data_pca)

#プロットの設定
#fig=plt.figure(figsize=(10,6),facecolor='w')
fig=plt.figure(figsize=(20,12),facecolor='w')

plt.rcParams["font.size"] = 10
i = 0
while i < length_data:
    #点プロット
    plt.plot(data_pca[i][0], data_pca[i][1], ms=5.0, zorder=2, marker="x", color=words[i][1])
 
    #文字プロット
    plt.annotate(words[i][0], (data_pca[i][0], data_pca[i][1]), size=12)
 
    i += 1

plt.show()


# ## プロットの結果
# プロットの結果、なんとなく近い単語が集まっている。
# 例えば、「was」「or」「a」「is」などのstopwordに設定されやすい単語が集まっているのがわかるかと思います。

 

独学で挫折した人向け・AI(機械学習)を短期間で学ぶ方法

独学で挫折してしまった
本買ったり、YoutubeでAIを勉強していたんだけど、結局から何を勉強してよいかわからず挫折してしまったんだ。どうしたら解消できる?

 

PythonをAI(機械学習)について、短期間で効率的に学ぶ方法を紹介します。

それは、以下のようなサービス、プログラミングスクールを利用することです。

プログラミングスキルを習得している人でも機械学習の習得は、難しいため、独学で迷うよりは、プロに教えてもらったほうが遥かに最短経路で身につけることができます。

 

関連記事

いますぐにでもAI(機械学習)が学べるプログラミングスクールを検討している方へ! [afTag id=2402] [template id="10277"]   筆者について 筆者は、AIプログラミン[…]

 

まとめ

自然言語のkaggleのコンペや、ユーザーの動向を調査するのに可視化は大事ですね。

可視化にword2vecによる分散表現を取り入れてみてはいかがでしょうか?

\IT未経験者からのサポートあり!転職サービス3選!!/

サービス名
未経験 未経験OK 未経験の転職専用 経験者向け
公開の求人数 ITエンジニア全体で1万件以上
ITエンジニア未経験で600件以上
未公開 5,000件以上
利用対象 全職種 IT特化 IT特化
特徴 ✓誰もが知る転職サービス
✓経歴を登録しておくとオファーが来る
✓企業担当者と条件交渉
✓スキルの身につく企業を紹介
✓IT専門のエージェントが対応
✓転職成功すると年収200万円以上の大幅アップがある
転職サポート内容
  • 求人検索
  • 企業担当者と交渉
  • 求人紹介
  • ライフプランのサポート
  • キャリア相談
  • 求人紹介
  • 提出書類の添削
  • 面接対策
公式サイト リクナビネクスト テックゲート レバテックキャリア
最新情報をチェックしよう!
>プログラミングスクール検索・比較表サイト

プログラミングスクール検索・比較表サイト

ワンクリック、さらに詳細に条件を指定してプログラミングスクールの検索ができます。さらに比較表により特徴を細かく比較できる!

CTR IMG