システムとモデリング

modelica, Julia, Design Structure Matrix, SysML, 他モデリング全般について。

最も優秀なタイプは?ポケモンのタイプ相性をネットワーク分析する。

グラフ理論・ネットワーク分析の勉強も進んできたのでそれらを応用して、ポケモンのタイプ相性をネットワーク分析してみたいと思います。

隣接行列の作成

ネットワークをプロットする基になる隣接行列を作成します。 まず、ポケモンの公式サイトからタイプ相性表をもってきます。 f:id:Otepipi:20190430121035p:plain:w1800

バトルに役立つ! タイプ相性表を公開!|『ポケットモンスター サン・ムーン』公式サイト

行が攻撃側の技のタイプ、列が防御側タイプになっています。また、「効果がばつぐん」は、「いまいとつ」は、「効果がない」は×、「ふつう」は無印です。

今回作成する隣接行列は、行列の要素に重みをつけたものにします。この重みの数値で「ばつぐん」「いまひとつ」「効果がない」「ふつう」を表現することにします。

この相性表に則って隣接行列を作成し、heatmapで可視化したものが以下になります。(クリックで拡大してください) f:id:Otepipi:20190430121043p:plain

重みは以下のように設定しています。

効果 重み
ばつぐん 3
ふつう 2
いまひとつ 1
効果がない 0

例えば

ほのおタイプの技をみずタイプが受けると「いまひとつ」

は行列の「ほのお」行と「みず」列が交わる要素の値が「1」であることから確認できます。

ネットワークの可視化と分析

作成した隣接行列を有向グラフとしてプロットしたものが以下です(クリックで拡大してください)

f:id:Otepipi:20190430121117p:plain:w1800

各ノード(赤丸)はそれぞれのタイプを表しています。 また、各ノードをつなぐエッジ(辺)には矢印がついており、矢印の根本が攻撃側、矢印の先が守備側です。 また、エッジの色は重みを表しており、以下のようになっております。

効果 エッジの色
ばつぐん 赤茶
ふつう
いまひとつ
効果がない エッジなし

タイプが18種類もありますので、エッジの数は今回316本もありますので大変見づらいグラフになります。完全グラフ+ループなので構造としてはシンプルなのですが。

続いてこのグラフから、最も"優秀な"ノード(=タイプ)を求めます。

今回、こちらの主観でタイプの"優秀さ"を以下のように定量化します。

「優秀さ」= 「ノードから出るエッジの重みの和」-「ノードに入るエッジの重みの和」

ここで「ノードから出るエッジの重みの和」は、技のタイプとしての優秀さを表します。この値が大きいほど、この技のタイプを使用した時に「効果がばつぐん」なタイプが多いことになります。

「ノードに入るエッジの重みの和」は、このタイプが守備に回ったときの優秀さを表すもので、この値が小さいほど、「効果がいまひとつ」になる技のタイプが多いことになります。

(ネットワーク分析ではノードの"中心性"を求める方法に「次数中心性」があるのでそれを応用したものになります)

では、各ノード(タイプ)の優秀さを計算し、その大きさをノードの色で表したプロットを以下に示します。そのタイプが優秀であるほど、色は赤に近づきます。(クリックで拡大してください)

f:id:Otepipi:20190430121320p:plain:w1800

今回の検証でははがねタイプが一番優秀となりました。もちろん、優秀さの定義は様々ですのでこれは一例に過ぎません。

参考として今回計算した優秀さの一覧を載せておきます。皆さんの感覚と一致しているでしょうか?

タイプ 優秀さ
はがね 8
フェアリー 3
ゴースト 3
ほのお 3
みず 2
じめん 2
ひこう 2
あく 0
いわ 0
でんき -1
どく -1
ドラゴン -1
かくとう -2
ノーマル -3
こおり -3
エスパー -3
むし -4
くさ -5

最後に今回使用したプログラムを載せて終わります。今回はMatlabを使用しました。

type={'ノーマル', 'ほのお', 'みず', 'でんき', 'くさ', 'こおり', 'かくとう', 'どく', 'じめん', 'ひこう', 'エスパー', 'むし', 'いわ', 'ゴースト', 'ドラゴン', 'あく', 'はがね', 'フェアリー'}

% ばつぐん3 通常2 いまひとつ1 効果がない0
% 行ラベルの攻撃側、列が防御側

data=[2 2 2 2 2 2 2 2 2 2 2 2 1 0 2 2 1 2;
    2 1 1 2 3 3 2 2 2 2 2 3 1 2 1 2 3 2;
    2 3 1 2 1 2 2 2 3 2 2 2 3 2 1 2 2 2;
    2 2 3 1 1 2 2 2 0 3 2 2 2 2 1 2 2 2;
    2 1 3 2 1 2 2 1 3 1 2 1 3 2 1 2 1 2;
    2 1 1 2 3 1 2 2 3 3 2 2 2 2 3 2 1 2;
    3 2 2 2 2 3 2 1 2 1 1 1 3 0 2 3 3 1;
    2 2 2 2 3 2 2 1 1 2 2 2 1 1 2 2 0 3;
    2 3 2 3 1 2 2 3 2 0 2 1 3 2 2 2 3 2;
    2 2 2 1 3 2 3 2 2 2 2 3 1 2 2 2 1 2;
    2 2 2 2 2 2 3 3 2 2 1 2 2 2 2 0 1 2;
    2 1 2 2 3 2 1 1 2 1 3 2 2 1 2 3 1 1;
    2 3 2 2 2 3 1 2 1 3 2 3 2 2 2 2 1 2;
    0 2 2 2 2 2 2 2 2 2 3 2 2 3 2 1 2 2;
    2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 1 0;
    2 2 2 2 2 2 1 2 2 2 3 2 2 3 2 1 2 1;
    2 1 1 1 2 3 2 2 2 2 2 2 3 2 2 2 1 3;
    2 1 2 2 2 2 3 1 2 2 2 2 2 2 3 3 1 2]

h = heatmap(type,type,data,'ColorbarVisible','off');
h.XLabel = '守備側';
h.YLabel = '技のタイプ';

G = digraph(data,type);

p=plot(G,'Layout','force','EdgeAlpha',0.5,'NodeColor','r','MarkerSize',10)
%エッジの重みに応じてエッジの太さを変える
%p.EdgeCData = G.Edges.Weight;
%colormap jet

type_attack_ranks = centrality(G,'outdegree','Importance',G.Edges.Weight);
type_defence_ranks = centrality(G,'indegree','Importance',G.Edges.Weight);

type_ranks = type_attack_ranks - type_defence_ranks;

p.NodeCData = type_ranks;
colormap(flip(autumn,1));
colorbar

今回はここまでにします