LoginSignup
20
5

More than 3 years have passed since last update.

networkxによるポケモンのゲームタイトルプレイ傾向の可視化

Last updated at Posted at 2020-03-29

はじめに

とあるポケモン研究者が作成した、
ポケモンらしさアンケートの結果分析をお手伝いすることになった。

今回はアンケート回答者が遊んだポケモンのゲーム18作品のプレイ傾向の可視化networkxライブラリで行った件についての記事である。

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
お手伝いしたポケモン研究者の
「ポケモンらしさ」についての研究記事その1
https://pkmnheight.blogspot.com/2020/03/1.html
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

対象の18作品
1. '赤/緑/青 Red/Blue'
2. 'ピカチュウ Yellow'
3. '金/銀 Gold/Silver'
4. 'クリスタル Crystal'
5. 'ルビー/サファイア Ruby/Sapphire'
6. 'ファイアレッド/リーフグリーン FireRed/LeafGreen'
7. 'エメラルド Emerald'
8. 'ダイヤモンド/パール Diamond/Pearl'
9. 'プラチナ Platinum'
10. 'ハートゴールド/ソウルシルバー HeartGold/SoulSilver'
11. 'ブラック/ホワイト Black/White'
12. 'ブラック2/ホワイト2 Black 2/White 2'
13. 'X/Y'
14. 'オメガルビー/アルファサファイア Omega Ruby/Alpha Sapphire'
15. 'サン/ムーン Sun/Moon'
16. 'ウルトラサン/ウルトラムーン Ultra Sun/Ultra Moon'
17. "Let's Go!ピカチュウ/Let's Go!イーブイ Let's Go, Pikachu!/Let's Go, Eevee!"
18. 'ソード/シールド Sword/Shield'


18集合ベン図は今の人類には不可能???

元々そのポケモン研究者からの依頼では
「18作品のプレイ傾向についてのベン図を作ってほしい」とのことだった。(うろ覚え)

ベン図とは、複数の集合どうしの関係を視覚化したもの(下図)。


http://www.mathlion.jp/article/ar093.html

調べてみると、人類はベン図との相性が良くないらしい。
3集合 のベン図までは普段目にすることも多いが、

unnamed.png

7集合の時点でこのザマである。もはや人間には何も理解できないだろう(R言語のvennライブラリで描けるらしい)

image.png
https://stackoverflow.com/questions/32440128/nice-looking-five-sets-venn-diagrams/40048520

そして2012年にヴィクトリア大学のKhalegh Mamakani,Frank Ruskey両氏によって11集合のベン図が発見された。これが現在、人類が到達した最大次元のベン図らしい。

A New Rose : The First Simple Symmetric 11-Venn Diagram
image.png
image.png
https://arxiv.org/abs/1207.6452

今の自分に18集合のベン図は不可能だということがわかった。

networkxによる可視化

ベン図で18集合は無理だが、最近趣味で始めたnetworkxでなら可視化できるかもしれない。目的は、ベン図を作ることではなく、

  • どの作品が多く遊ばれているか。
  • ある作品を遊んでる人が、多く遊んでいるのはどれか。

が可視化できればいいので、
最終的にこのようなグラフを作成した。
out.png

各ノード(円のこと)の内側がポケモンのゲームタイトルを表す、ポケモンファンに馴染みの深い略称となっている。接頭句の「01_」はタイトルの発売された順番を表す。

ノードの大きさは各作品を遊んだ人数の規模
エッジ(各ノードを結ぶ線)の太さは各2作品を遊んだ人数の多さをjaccard係数によって表現。

jacccard係数

J(A,B) =  \frac {\begin{vmatrix}A \cap B\end{vmatrix}} {\begin{vmatrix}A \cup B\end{vmatrix}} 

ノードの色は

  • 濃い赤:完全新作
  • オレンジ:リメイク版
  • 薄いオレンジ:マイナーチェンジ版

を表す。

ある作品を遊んだ人はどの作品も遊んでるか。の傾向が可視化できていると思う。
例えば、以下のような傾向が見える。

  • DP,BWを遊んだ人数が特に多い。
  • マイナーチェンジ版は遊ばないが、完全新作は遊ぶ人がいる。
  • RS以降の完全新作と、最新作である剣盾を共に遊ぶ人は多い。
  • 赤緑青と剣盾を共に遊んだことのある人が少ない。

pythonでの処理

全コードと、元データは私のgithubにあげておきます。
https://github.com/mrok273/

まず、以下のようにone-hotの状態のデータフレームを作成。
image.png

全18作品の2作品組み合わせを作成


import itertools
combination_list = list(itertools.combinations(list(node_list), 2))

"""
Out:
[('01_赤緑青', '02_ピ'),
 ('01_赤緑青', '03_金銀'),
 ('01_赤緑青', '04_ク'),
 ('01_赤緑青', '05_RS'),
...
"""

各2タイトル間のjaccard係数を計算。

for (n1,n2) in combination_list:
    Union_df = df[(df[n1]==1) | (df[n2]==1)]
    Intersection_df =df[(df[n1]==1) & (df[n2]==1)]
    n1_list.append(n1)
    n2_list.append(n2)
    Union_list.append(Union_df.shape[0])
    Intersection_list.append(Intersection_df.shape[0])

df_ja = pd.DataFrame({"n1":n1_list,
             "n2":n2_list,
             "Union":Union_list,
             "Intersection":Intersection_list})
df_ja["jaccard_value"] = df_ja["Intersection"] / df_ja["Union"]
n1 n2 Union Intersection jaccard_value
01_赤緑青 02_ピ 13606 7823 0.574966926
01_赤緑青 03_金銀 14345 9902 0.690275357
01_赤緑青 04_ク 13697 6667 0.486748923
01_赤緑青 05_RS 17210 9507 0.552411389
01_赤緑青 06_FRLG 16331 7868 0.481783112

networkxによるグラフの設定

import networkx as nx
import matplotlib.pyplot as plt
import japanize_matplotlib
import numpy as np

G = nx.Graph() #グラフの作成
G.add_nodes_from(node_list) #ノードの作成

# エッジの追加
for i in range(len(df_ja)):
    row_data = df_ja.iloc[i]
    G.add_edge(row_data['n1'], row_data['n2'], weight=row_data['jaccard_value'])

#グラフの表示
plt.figure(figsize=fig_size) 

#ネットワーク図の表示設定。circular_layoutを使用
pos = nx.circular_layout(G) 

networkxに他にどのようなレイアウトがあるかは
NetworkX本家のチュートリアルを参照
https://networkx.github.io/documentation/stable/reference/drawing.html

グラフの見栄えをマシにする

各作品を遊んだユーザー数は、差はあれど、一番大きい値と小さい値でせいぜい2倍ちょっと。

これではグラフネットワークを作成しても、人数の差が実感しにくくなってしまう。
image.png

そのため、各タイトルごとのプレイ人数差を、最大数によって正規化し、さらにべき乗することで、 差を極端に開かせる処理を行った

  • 処理前
    image.png

  • 処理後:各タイトルごとの相対的な差が広まっている
    image.png

エッジの太さについても同様の処理を行う

player_dict={} # 各タイトルのプレイヤー数を収納
for gen in node_list:
    player_dict[gen] = df[gen].sum()

# ノードの描画上の大きさの設定。数が多いと比較が難しくなるので、差を強調
#また、
node_size=[(v-4000)**2*10000/(max(player_dict.values())**2) for v in player_dict.values()]

def make_node_color(node_list):
    #マイナーチェンジ版。リメイク版に異なる色をつける処理
    minor_change=['02_ピ','04_ク','07_Em','09_Pt', '12_BW2','16_USUM']
    remake=['06_FRLG', '10_HGSS','14_ORAS', '17_ピカブイ']
    color_list=[]
    for node in node_list:
        if node in minor_change:
            color = 3000
        elif node in remake:
            color = 6000
        else:
            color = 10000
        color_list.append(color)
    return color_list

node_color = make_node_color(node_list)

# グラフにノードを描画。ノードの色・大きさはここで設定
nx.draw_networkx_nodes(G, pos, node_color=node_color,
                       cmap=plt.cm.Reds,
                       alpha=0.7,
                       node_size=node_size)

# 日本語ラベル
nx.draw_networkx_labels(G, pos, fontsize=20, font_family='IPAexGothic', font_weight="bold")

# エッジの太さ調節.こちらも差を強調する
edge_width = [np.exp(d["weight"]-0.3)**5 for (u, v, d) in G.edges(data=True)]

# エッジの描画
nx.draw_networkx_edges(G, pos, alpha=0.4, edge_color=edge_width, width=edge_width,edge_cmap=plt.cm.Blues)

plt.axis('off')

これで各タイトルの関係性がより強調され、見やすくなった。
image.png

最後に

networkxは、pandasライブラリなどに比べて使う人が少ないため、目的に合った記事が見つかりにくいかもしれない。が、matplotlibやseabornでは表せない表現も可能ではある。
ただし、分かりやすい可視化のためには試行錯誤が必要で、色や大きさを整理することは必要。
自分もまだまだnetworkxについては知らないことが多い。

20
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
5