u++の備忘録

Poincaré Embeddings でJ1リーグのチーム・選手を可視化

ふと「Poincaré Embeddings」*1で遊んでみたいと思い立ち、サッカーJ1リーグのデータで試してみました。

Poincaré Embeddings

Poincaré Embeddingsに関する説明は、ABEJA*2やscouty*3のブログに譲ります。

Poincaré Embeddings は端的に言うと word2vec の埋め込み先をユークリッド空間ではなく双曲空間にするという手法で、階層構造やべき分布をもつデータを埋め込むという問題設定において、低次元でもよい表現を与えられるという特徴があります。

Poincaré Embeddings による職種の類似度計算とその利用 - LAPRAS AI LAB

gensimでの実装とデータセット

Poincaré Embeddingsを手軽に試すに当たって、gensimでの実装*4が存在します。

この実装に渡すデータセットの形式は次の通りです。データセットはタプルを要素に持つリスト形式で、各タプルは('選手名', 'チーム名')のような関係性を持っています。

[('アウグスト ペドロ デ ソウザ', '鹿島アントラーズ'),
 ('アウグスト ペドロ デ ソウザ', '川崎フロンターレ'),
 ('アジエル アモリム', '湘南ベルマーレ'),
 ('アジエル アモリム', '浦和レッズ'),
 ('アデミウソン', '横浜F・マリノス'),
 ('アデミウソン', 'ガンバ大阪'),
 ('アドリアーノ フェヘイラ', 'セレッソ大阪'),
 ('アドリアーノ フェヘイラ', 'ガンバ大阪'),
 ('アマラオ', 'FC東京'),
 ('アマラオ', '湘南ベルマーレ')]

一般にこのような形式で存在しているデータセットはさほど多くなく、今回も全工程の中で特にデータセットを作る部分に苦心しました。

今回は「J1リーグの各チームの歴代所属選手の可視化」という題材に落とし込むことで、Poincaré Embeddingsに適した階層構造を持つデータセットを準備できました。収集には「FootballGEIST」*5を利用しています。具体的には、J1リーグ全18チームそれぞれの歴代所属選手のページからデータを収集し、gensimの実装に渡せる形式にpandasで加工しました。

Poincaré Embeddingsの学習

パッケージのインポートをします。ここでplotlyのバージョンが3以上だと可視化の際にエラーが出ます*6

from gensim.models.poincare import PoincareModel
from gensim.viz.poincare import poincare_2d_visualization
from IPython import display
from plotly.offline import init_notebook_mode, iplot
import pandas as pd
 
init_notebook_mode(connected=True)

環境に入っているバージョンを確認し、必要ならば2.7.0辺りのバージョンを入れておきます。

# import plotly
# plotly.__version__
# '2.7.0'

!pip install plotly==2.7.0

先の節で用意したデータセットを用いて、Poincaré Embeddingsの学習を実行します。今回の場合、epochsは2000回程度で十分なようでした。

model = PoincareModel(train_data, size=2, negative=8)
model.train(epochs=5000)

次のコードでplotlyでの可視化を実行できます。show_node_labelsにはラベルを付ける項目を指定します。

relations_set = set(train_data)
figure_title = ''
iplot(poincare_2d_visualization(
    model,
    relations_set,
    figure_title,
    num_nodes=0,
    show_node_labels=['浦和レッズ'] + urawa
))

可視化の結果は次の通りです。チーム名が中心に来て、円周側に選手が配置されています。 gensimの実装では正則化の影響で周囲にノードが集結しすぎないような工夫がなされているため、ある程度の数のノードが中心付近に残っている模様です*7

f:id:upura:20190901021328p:plain

浦和レッズ所属経験のある選手にラベルを付与したところ、大半は右下に固まりました。興味深いのは、チーム名としての「浦和レッズ」の近くに「サンフレッチェ広島」が配置されている点です。森脇・柏木・槙野・西川・闘莉王など、サンフレッチェ広島から浦和レッズに移籍した選手の影響ではないかと推察しています。

次の図では、インタラクティブにデータを閲覧できます。

ちなみに、次のtwitterの投稿の際は学習が不十分だった模様です。


活用方法

個々のベクトルの値は、次のような形で参照できます。

model.kv['浦和レッズ']
array([ 0.64337554, -0.49962734])

得られたベクトルの活用方法としては、例えば一定の括りで少数派に当たるデータをまとめ上げる、類似するデータを検索するなどの方法が考えられます。Kaggleなど教師あり学習の文脈では、カテゴリ変数の粒度が粗い場合などに、活用の余地があり得るかなと思いました。

おわりに

本記事では、Poincaré Embeddings でJ1リーグのチーム・選手を可視化しました。実装はNotebook形式でGitHubにて公開しています*8