gensimをPythonで使用して、chive-1.2-mc5.kvというword2vecの事前学習済みモデルを使用して、単語の類似度リストアップや足し算引き算を行いました。
以下のような類似ベクトルの単語を類似度順にリストアップしたり、単語同士の足し算引き算を行うことも可能です。
単語入力して: 東京
[('大阪', 0.627456784248352),
('名古屋', 0.6259051561355591),
('都内', 0.6223526000976562),
('横浜', 0.6177170872688293),
('新宿', 0.6033221483230591),
('神奈川', 0.5992082357406616),
('渋谷', 0.597951352596283),
('東京都', 0.5948487520217896),
('六本木', 0.5921141505241394),
('トウキョウ', 0.5762448906898499)]
0,Word2Vecとは?単語のベクトル解析をどう使う??
Word2Vecは、ニューラルネットワークを用いて、単語の分散表現を学習したものです。
分散表現ってのが何かわからなかったので、ChatGPTに相談しました。
分散表現とは、複数の要素で構成されたベクトルで表される単語の意味表現のことです。具体的には、各単語を固定長のベクトルで表現することができます。
ChatGPTより
例えば単語をベクトルにすることで、単語の四則演算を可能とします。
「アップル」-「フルーツ」=「ジョブズ」
みたいな感じです。
実際にやってみると...
「携帯電話」-「スマホ」の結果です。
[('ポケットベル', 0.35510846972465515),
('ファクシミリ', 0.33402299880981445),
('バラカート', 0.3288613259792328),
('通信機器', 0.3240174651145935),
('電話', 0.32167190313339233),
('モンゾガンチァンイク', 0.31471771001815796),
('発信機', 0.3060969412326813),
('電子メール', 0.304851770401001),
('逆探知', 0.296607106924057),
('通信機', 0.2923787832260132)]
この場合だと、スマートフォン以外の遠隔意思疎通手段、ポケベルやFAXなどが上位に来ましたね。
単語の四則演算を応用して単語間の類似性・関連性を算出できます。
例えば......
「東京」という単語に強く関連がある単語上位10件です。
[('大阪', 0.627456784248352),
('名古屋', 0.6259051561355591),
('都内', 0.6223526000976562),
('横浜', 0.6177170872688293),
('新宿', 0.6033221483230591),
('神奈川', 0.5992082357406616),
('渋谷', 0.597951352596283),
('東京都', 0.5948487520217896),
('六本木', 0.5921141505241394),
('トウキョウ', 0.5762448906898499)]
大都市や東京と関わりの深い地名が出てきましたね。
1,「gensim」を用いたWord2Vecの準備
環境構築など
pip install gensim
学習済みモデルをダウンロード。
学習には約1億のウェブページ文章を含む国立国語研究所の日本語ウェブコーパス(NWJC)を採用し、分かち書きにはワークスアプリケーションズの形態素解析器Sudachiを使用しています。
https://github.com/WorksApplications/chiVe
モデルファイルをダウンロード&配置
モデルファイルを置いたディレクトリで右クリックしてターミナルを開きます。
圧縮されてるので、ターミナルで「tar -xzf (ファイル名).tar.gz」とし展開します。
2,Word2Vecで遊ぼう!!
今回は「chive-1.2-mc5.kv」を使います。
単語のベクトルを比較し、関連性上位の単語を出力して遊ぶ
単語を300次元のベクトルとして表しているため、四則演算を単語に対して行えます。
そこで、まずは入力した単語に似た単語をベクトルの一致度合い付きで出力してみます。
関連性の高い単語発見プログラムですね!!
以下のコードをコピペしてください。
import gensim
from pprint import pprint
# chiVeデータのPATH(kv:KeyedVectors)
model_path = "C:/Users/loveanime/Desktop/test/chive-1.2-mc5_gensim/chive-1.2-mc5.kv" # モデルの読み込み
wv = gensim.models.KeyedVectors.load(model_path)
while True:
keyword = input("\n単語入力して: ")
try:
# 類似度上位10件を取得
match = wv.most_similar(keyword, topn=10)
pprint(match)
except:
pass
mode_pathは適当に置き換えます。
初回実行時はRAMにモデルが乗るまで少々待ちます。
あとは遊ぶだけです。
なお該当する単語がない場合エラーとなるのですが、そのようなエラーが出ても落ちずに次の入力を待つようにしてます。
アニメ関連の用語とか入力すると楽しい☆
単語入力して: fate
[('staynight', 0.8614016175270081),
('リトバス', 0.6792396306991577),
('clannad', 0.6701553463935852),
('月姫', 0.664059042930603),
('シュタゲ', 0.6400308609008789),
('ブラクラハルヒ', 0.637483537197113),
('クラナド', 0.636178195476532),
('kanon', 0.6220419406890869),
('アンリミテッドコード', 0.6208119988441467),
('hollow', 0.6169981360435486)]
fate の関連最上位が staynightで嬉しいですね。
クラナド シュタゲなどアニメ当時に流行ったものが関連性大となってます。
単語入力して: 戦場ヶ原
[('阿良', 0.6806783676147461),
('ガハラ', 0.6490923762321472),
('忍野', 0.6282691359519958),
('真宵', 0.6230186820030212),
('羽川', 0.6158154010772705),
('サイトロゴコトブキヤ', 0.6097046732902527),
('パズルジガゾーパズル', 0.5674473643302917),
('神原', 0.5642620325088501),
('シリーズセカンドシーズンマイクロファイバーミニタオル', 0.5591721534729004),
('貮', 0.5441311001777649)]
物語シリーズのヒロインを差し置いて阿良々木さんが関連度上位です。
良かったですね。
単語入力して: 東京
[('大阪', 0.627456784248352),
('名古屋', 0.6259051561355591),
('都内', 0.6223526000976562),
('横浜', 0.6177170872688293),
('新宿', 0.6033221483230591),
('神奈川', 0.5992082357406616),
('渋谷', 0.597951352596283),
('東京都', 0.5948487520217896),
('六本木', 0.5921141505241394),
('トウキョウ', 0.5762448906898499)]
例が二次元寄りですが、別にヲタク系に限らずちゃんと関連性評価してますヨ!
ということで「東京」でした。
単語のベクトルを引き算して遊ぶ
import gensim
from pprint import pprint
# chiVeデータのPATH(kv:KeyedVectors)
model_path = "C:/Users/loveanime/Desktop/test/chive-1.2-mc5_gensim/chive-1.2-mc5.kv"
wv = gensim.models.KeyedVectors.load(model_path)
while True:
keyword_postive = input("\n「A-B」のA部分の単語入力して: ")
keyword_negative = input("\n「A-B」のB部分の単語入力して: ")
try:
result = wv.most_similar(positive=keyword_postive, negative=keyword_negative)
pprint(result)
except:
pass
先程の関連性の高い単語探し同様に、モデルパスを自身の環境に合わせて書き換え、初回実行時少し待ちます。
以下いくつか例です。
「A-B」のA部分の単語入力して: 世界
「A-B」のB部分の単語入力して: 日本
[('仮想現実', 0.3568820357322693),
('別世界', 0.33659353852272034),
('並行世界', 0.32004809379577637),
('パラレルワールド', 0.31889134645462036),
('ルゲヱ', 0.31139951944351196),
('次元', 0.3107324540615082),
('目眩く', 0.31034454703330994),
('ソツナング', 0.30991509556770325),
('人界', 0.3090641498565674),
('現界', 0.3088890612125397)]
「世界」ー「日本」で仮想世界系とは意外ですね。
外国とか出るのかと思えば次元が違うとか異世界行くとかな感じです。
「A-B」のA部分の単語入力して: 戦場ヶ原
「A-B」のB部分の単語入力して: アニメ
[('小来', 0.3734552562236786),
('中禅寺湖', 0.36332476139068604),
('忍野', 0.3486372232437134),
('霧降', 0.31107524037361145),
('沼山', 0.31054118275642395),
('中禅寺', 0.30991023778915405),
('青葉山', 0.304657518863678),
('八溝', 0.30026182532310486),
('小田代原', 0.29964902997016907),
('茂林', 0.29871517419815063)]
先程の類似度を踏まえ、「戦場ヶ原」から「アニメ」を引いてみるとただの地名・名字になりました。
これは感覚と一致しますね。
「A-B」のA部分の単語入力して: 祖父母
「A-B」のB部分の単語入力して: 祖父
[('保育者', 0.3847978413105011),
('保護者', 0.3730812072753906),
('就学', 0.369486927986145),
('就園', 0.36835938692092896),
('共働き', 0.36568504571914673),
('在園', 0.3550587296485901),
('保育', 0.35173431038856506),
('共稼ぎ', 0.3516617715358734),
('転園', 0.346963495016098),
('DINKS', 0.3465498685836792)]
「祖父母」ー「祖父」は、パッと見「祖母」が出そうですが、冷静に考えると「祖母」も「祖父」と高い関連性をもつので、一緒にマイナスされて出てきません。
他にも言語処理関連の様々なプログラムをAI中心に動かしているので、ぜひ合わせてご覧ください。