やること
前編ではポケモンの名前を生成するためのベイジアンネットワークを構築し、サンプリングして遊びました。
ベイジアンネットワークのより効果的な使い方として、ノードの一部を指定した状態から他のノードをいい感じに生成(推定)することができるようです。ここでは名前の一部を指定しながら新しいポケモン名を生成してみます。
条件付きサンプリングの方法
ネットワークの定義とデータを用いた学習(=CPDを求める)までは前編と同じです。その後、サンプリングルする部分を改造していきます。
条件付きのサンプリングは文献が少ないので公式マニュアルをご参照ください。
pgmpy.sampling.BayesianModelSampling.likelihood_weighted_sample() と同 rejection_sample() があります。両方試してみましたが、おそらくやりたいことは後者かなと思います。
まずは2文字目を小さい「ッ」に限定して50回生成してみます。生成後は重複を除き、学習データにないものだけを表示します。
from pgmpy.factors.discrete import State
#条件
evidence = [State('c2', 'ッ')]
#一部を指定した条件付きサンプリング
sampler = BayesianModelSampling(model)
new_data = sampler.rejection_sample(size=50, evidence=evidence)
#列の並び替え
new_data = new_data[['head', 'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8']]
#全サンプルの出力
#print(new_data)
#重複行を削除
new_data = new_data.drop_duplicates()
#データセットにある行を削除
new_data = new_data.merge(data, indicator=True, how='outer').query('_merge=="left_only"').drop('_merge', 1)
#新規かつ重複のないサンプルを出力
print(new_data)
head c1 c2 c3 c4 c5 c6 c7 c8
4 * ポ ッ タ :A * * * *
8 * ラ ッ キ ン グ * * *
9 * テ ッ ポ * * * * *
10 * テ ッ シ ー * * * *
11 * ナ ッ シ ブ ー ン * *
12 * マ ッ シ ー ド * * *
13 * ム ッ ク ラ ー * * *
14 * ム ッ ク ラ ゲ * * *
16 * ナ ッ シ ブ ー * * *
17 * レ ッ ク ラ ー * * *
18 * ポ ッ ポ ウ オ * * *
21 * レ ッ ク ル * * * *
23 メガ レ ッ ク ル ス * * *
26 * ケ ッ キ ー * * * *
27 * マ ッ シ ー * * * *
28 * ポ ッ タ * * * * *
29 * ポ ッ チ ャ ム * * *
32 * ナ ッ ク ル ス * * *
33 * レ ッ ク ル ス * * *
35 * ポ ッ チ ー ル * * *
サンプリングにそこそこ時間がかかりましたが、いい感じにできています。2文字目に「ッ」があると軽快な感じがしますね。ちなみに2文字目が「ッ」のポケモンは本来は31種います。
ナッシブーン、強そうな響きですね。
他の条件でも試してみる
2文字目に小さな「ャ」
2文字目に小さな「ャ」はどうでしょうか。(本来は23種)
#条件
evidence = [State('c2', 'ャ')]
head c1 c2 c3 c4 c5 c6 c7 c8
2 * ギ ャ ロ ッ ク * * *
3 * チ ャ ー ス * * * *
5 * ジ ャ ロ ー * * * *
9 * ジ ャ ラ ラ ン * * *
11 メガ ギ ャ ロ ッ ク * * *
13 * シ ャ ワ ー ル * * *
14 メガ チ ャ ー ス * * * *
15 * ジ ャ ロ ッ グ * * *
16 メガ ダ ャ チ マ ル * * *
18 * ニ ャ オ ブ ー ン * *
20 * ニ ャ ー レ ム * * *
23 メガ ギ ャ ラ ン ♂ * * *
24 * ジ ャ ラ ン ス * * *
25 * シ ャ ン デ ィ * * *
26 * ギ ャ ラ ン ゴ * * *
28 * ジ ャ ラ ド ス * * *
チャースとメガチャースはチャラめの後輩ですね。
3文字目に「ー」
3文字目に「ー」があるとオシャレかなと思っています。(本来は54種)
#条件
evidence = [State('c3', 'ー')]
head c1 c2 c3 c4 c5 c6 c7 c8
0 * フ リ ー セ ン * * *
2 * フ ロ ー ン * * * *
4 * ア マ ー ジ ャ * * *
5 * チ リ ー ラ * * * *
6 * フ ラ ー ド ン * * *
7 * ゴ ル ー * * * * *
9 * グ ラ ー ジ ョ * * *
10 * リ リ ー プ * * * *
11 * グ ラ ー ジ オ * * *
14 * リ リ ー ザ ー * * *
15 メガ リ ザ ー ド * * * *
17 メガ ヨ ポ ー ポ ュ ェ * *
23 * ス タ ー ジ オ * * *
25 * ハ リ ー ザ ー * * *
27 * ジ ラ ー ジ オ * * *
28 * チ ャ ー ス * * * *
33 * チ リ ー ラ イ * * *
35 * ツ タ ー ジ オ * * *
36 * チ ャ ー ス :A * * *
37 * ポ ニ ー ゴ * * * *
40 * ド ゴ ー ム ド * * *
41 * ゴ ル ー ド ン Y * *
まさかのチャース(アローラのすがた)。
4文字目に「ド」
4文字目に「ド」がある~ドン、~ドスは強そうですね。(本来は28種)
#条件
evidence = [State('c4', 'ド')]
head c1 c2 c3 c4 c5 c6 c7 c8
0 * カ バ ル ド * * * *
1 * ジ ャ ラ ド ス * * *
3 メガ リ ザ ー ド ン * * *
4 * マ ユ ル ド ン Y * *
5 * マ ユ ル ド ン * * *
6 * ド サ イ ド ル * * *
7 * ニ ド リ ド リ (まいまい) * *
8 * サ ザ ン ド * * * *
9 メガ バ ン バ ド ロ * * *
12 * オ ン バ ド ロ * * *
17 * ニ ド リ ド リ (めらめら) * *
19 * ズ ガ イ ド ル * * *
20 * キ レ イ ド ス * * *
22 * ク サ イ ド ル * * *
25 * ジ ラ ー ド ン * * *
27 * ズ ガ イ ド ン * * *
28 * ゴ ル ー ド ン * * *
29 * ユ レ イ ド ス * * *
32 メガ ト ア ・ ド ゼ 特大 ド *
キレイドス(京ポケモン)
2文字目に「ー」、5文字目に「ン」
2文字目に「ー」、5文字目に「ン」はヒードランのパターンですね。強いんじゃないでしょうか。(本来は8種)
#条件
evidence = [State('c2', 'ー'), State('c5', 'ン')]
head c1 c2 c3 c4 c5 c6 c7 c8
2 メガ ド ー ブ シ ン * * *
3 * ド ー ブ シ ン * * *
4 * ホ ー ホ ー ン * * *
5 * ダ ー ク イ ン * * *
6 * コ ー タ ク ン * * *
7 * ド ー ド ラ ン * * *
10 * ガ ー デ ィ ン * * *
11 * ケ ー シ ャ ン * * *
13 * マ ー シ ャ ン * * *
14 * ド ー ド ラ ン ガ * *
15 * イ ー ブ シ ン * * *
17 * シ ー ド ラ ン * * *
期待したほどは強くなさそうでした。生成数は少なめですが妥当なものを出してくれています。
まとめ
条件付きのサンプリングでようやくベイジアンネットワークの威力を感じることができました。今度はネットワーク構造を機械で推定する形で使ってみようと思っています。
ナッシブーンのイメージ図を置いておきますね。