見出し画像

裏面土地はほんとにMTGアリーナの初手補正に影響したのか~17Landsのデータ解析をしてみた~

編集履歴

<2024/08/05>
 ・記事公開
<2024/08/07>
 ・記事のタイトルを微修正
 ・記事内の誤字脱字・わかりづらい表現を修正
 ・デッキ枚数40時の最頻値の出力結果が誤っていたので修正
  (結果に影響はありません)
 ・ソースコード公開

初めに

こんにちは。いずみんです。
MH3が6月にリリースされましたが、アリーナダイレクトというパチンコ競技性の高いイベントも新たに催されたため、ここ最近のセットの中で一番モチベーション高く遊んでました。
MH3リリース前に「MTGアリーナの初手補正に裏面土地は影響するか」という記事を公開しました。これはMH3で再録された裏面土地カードがアリーナのBo1初手補正にどのように影響するのか、Botを使って調べた記事です。

記事を書いた当時はMH3のリリース直後だったのでBotでの検証しか方法はありませんでしたが、リリースから1か月経過したため17LandsからプレイヤーのゲームのログであるPublic Data Setsが公開されました。
「このデータを活用すれば本当に裏面土地に初手補正あるのかわかるんじゃね?」
と思い立ったため、1.5か月前に書いた記事のアンサーとしてこの記事を書きました。

今回やること

以下の方針に従って解析を実施します。
①データの調査
 17LandsのPublic Data Setsデータをチェックして必要な情報を集めるための準備をします。
②データクレンジング
 17LandsのPublic Data Setsデータから初手補正に必要なデータを抽出します。
③解析
 算出したデータから初手に含まれた土地および裏面土地の割合を算出し、評価します。
データ解析をやったことなく、いろいろ調べるとPythonがよさそう。。。ということで半分興味本位でPythonで解析してみました。
(ちなみにコード書くのは10年ぶり)
やる前から地獄が見えるワクワクしますね!

①データの調査

データを持ってこよう

17Landsからデータを取得します。今回はPremierDraftのリプレイデータ(replay_data_public.MH3.PremierDraft.csv)を利用します。

https://www.17lands.com/public_datasets

リプレイデータは17Landsユーザーによって対戦時に生成される操作ログがまとまったデータです。圧縮されたファイルを解凍するとcsv形式で約4.68GBと大規模なデータが格納されていることがわかります。

でかい!説明不要!

データの中身を見てみよう

サイズにビビりましたが、兎にも角にもどういうデータなのか知らないと話が進みません。ファイルがでかすぎてSpreadsheetでは開かないので、PowerBIを使ってどんなデータが格納されているのか覗いてみます。
ざっと見た感じ、以下のことがわかりました。

  • 767,774行×約300列のデータです。

  • 各行にはプレイヤーがゲームを実施した時間や勝敗、デッキ情報、プレイ 時の操作情報が格納されてます。

  • deck_カード名の列が存在しており、各ゲームのデッキの中に含まれている枚数が数値データとして格納されています。

  • 初手のデータはcandidate_hand1に文字列として格納されています。 ただしIDという固有の数値データに置換されています。

初手です。マリガンしますか?

データクレンジングの方針を立てよう

前述の情報から必要なデータの算出方法を検討します。

  1. デッキの枚数はdeck_カード名の各列の合計で算出できそう。

  2. デッキに含まれる土地、裏面土地はdeck_カード名列の列名からひっかけて算出できそう。 

  3. 初手に何が来たのかは文字列を整形してカードID情報と突合すればなんとかなりそう。

この方針をもとに、Pythonを使って試行錯誤しながらデータを触っていきました。

②データクレンジング

前置き

この章では解析に必要なデータをPythonで生成した処理を説明します。
興味がない方は「③データ解析」まで飛ばしてください。
mtgとは関係ないですが、備忘と第三者の目で見てもらえれば何か気づきがあるかもという思いで残しています。ロジックに誤りがないように気を付けていますが、もし間違っている処理があればご指摘ください。(ソースは後程公開します。)
前述の通り、Python自体初めて触る&コード書くが10年ぶりなので、生暖かい目で見ていただければと思います。(特に変数名のセンスがないです)

実際の処理(ポイントだけ)

■事前処理
土地情報の収集です。17Landsからカード情報をダウンロードし、アリーナで実装されている土地タイプを持つカードのIDをすべて抽出します。データはデータ分析ライブラリであるpandasを利用してDataFrameに書き込みます。

#カード情報の収集
cardurl="https://17lands-public.s3.amazonaws.com/analysis_data/cards/cards.csv"
cardcol=['id','name','types']
carddf = pd.read_csv(cardurl,low_memory=False,usecols=cardcol)

#土地情報の収集
land=carddf[carddf['types'].str.contains('Land', na=False)]
landname=list(land['name'])
landid=list(land['id'])

裏面土地の定義です。
カード情報には表面の情報で登録されているため、表面のカード名のリストを作成します。カード情報からリストに一致するIDを抽出します。

#MDFCs情報の収集
mdfcsname=["Bloodsoaked Insight","Boggart Trawler","Bridgeworks Battle","Disciple of Freyalise","Drownyard Lurker","Glasswing Grace","Fell the Profane","Hydroelectric Specimen","Legion Leadership","Pinnacle Monk","Razorgrass Ambush","Revitalizing Repast","Rush of Inspiration","Sink into Stupor","Strength of the Harvest","Stump Stomp", "Sundering Eruption","Suppression Ray", "Waterlogged Teachings", "Witch Enchanter"]
mdfcsdf=carddf[carddf['name'].str.contains("|".join(mdfcsname))]
mdfcsid=list(mdfcsdf['id'])

■データの読み込み
リプレイデータを読み込んでみましたがOut of memoryで読み込めません。Public Data Setsには日付や操作情報など今回の解析では不要なデータが入っています。そのため不要なデータの削除や、データの型を指定して最適化することでメモリ不足の解消を図りますが、それでも読めなかったので、 10000行単位で読み込みを行います。

url = "https://17lands-public.s3.amazonaws.com/analysis_data/replay_data/replay_data_public.MH3.PremierDraft.csv.gz"
chunksize=10000
for replaydf in pd.read_csv(url, dtype=dtypes,low_memory=False,usecols=usecols,chunksize=chunksize):

これでリプレイデータが読み込めました。

■デッキ情報の算出
デッキ枚数、土地枚数、裏面土地数の情報を算出します。前述したとおりdeck_カード名列内にデッキに含まれる枚数が格納されているので、列名を条件にして合計値を算出し、デッキ枚数として格納します。
土地、裏面土地も同様です。先ほど定義した土地名と裏面土地名に該当するカードの枚数だけ選択して合計します。

 #デッキ情報の取得
 replaydf['num_deck']=replaydf.iloc[:,replaydf.columns.str.startswith('deck_')].sum(axis=1)
 replaydf['num_land']=replaydf.iloc[:,replaydf.columns.str.contains("|".join(landname))].sum(axis=1)
 replaydf['num_mdfcs']=replaydf.iloc[:,replaydf.columns.str.contains("|".join(mdfcsname))].sum(axis=1)

■初手情報の算出
初手は7枚のカードIDが文字列として連結されているので、これを分割して比較できるようリストにします。「リスト内のID」が「土地と裏面土地のID」に一致するかカウントします。ここまでの処理の結果と必要な列だけ新しいDataframeに格納します。

#ハンドの土地情報を収集 
for handstr in replaydf['candidate_hand_1']:
  hand=[]
  candidate_mdfcs=[]
  candidate_land=[]
  hand=list(map(int, handstr.split('|')))
  opening_land.append(len(list(filter(lambda x: x in landid,hand))))
  opening_mdfcs.append(len(list(filter(lambda x: x in mdfcsid,hand))))
 replaydf['opening_land']=opening_land
 replaydf['opening_mdfcs']=opening_mdfcs
 replaydf['deck_in_allland']=replaydf['num_land']+replaydf['num_mdfcs']
 replaydf['opening_in_allland']=replaydf['opening_land']+replaydf['opening_mdfcs']
 #統計情報のDataFrameに追加
 statdf=pd.concat([statdf,replaydf[['num_mulligans','num_deck','num_land','num_mdfcs','deck_in_allland','opening_land','opening_mdfcs','opening_in_allland']]])

 ここまでクレンジングした結果、14.6MBサイズまで削減することができました。ここまでの結果のデータをcsv形式で出力したデータおよびソースコードを本記事に添付します。

③データ解析

まず集計したデータの全体感をみてみましょう。
76万回のプレイで利用されたデッキ枚数の傾向を見ます。Pythonでデッキ枚数の出現頻度を見ます。

>>> statdf['num_deck'].value_counts()
num_deck
40    719701
41     39745
42      4845
43      1732
44       747
45       363
46       207
47       120
50       101
48        54
49        44
51        41
60        26
52        17
53        10
55        10
54         6
56         2
59         1

40枚〜60枚(!?)とバラツキがありますが、最頻値は40で全体の93%を占めてます。40以外はノイズになるので除外します。
次にデッキ内の土地と裏面土地の合計土地枚数の基準を決めます。同じくPythonで合計土地枚数での出現頻度を確認します。

>>> statdf[(statdf['num_deck']==40)]['deck_in_allland'].value_counts()
deck_in_allland
18    228116
17    220746
19    140392
20     63083
16     33053
21     23088
22      6757
15      1966
23      1916
24       394
14        94
25        69
13        21
26         6

最頻値は17,18と僅差なため、デッキ内の合計土地枚数は17、18で固定します。解析は合計土地枚数が17、18になるように裏面土地枚数を変更して、傾向を見ます。Pythonをこねくり回して、結果を算出します。

正規化されたデータ(土地17枚換算)
正規化されたデータ(土地18枚換算)

各検証のサンプル数の最小値及び最大値は以下の通りです。
 最小値 土地18(土地13-裏面5) 4641サンプル
 最大値 土地18(土地16-裏面2) 77503サンプル
最小値と最大値でばらつきはあるものの、サンプル数としては問題ないかと考えます。

考察

■裏面土地なしの補正
17-0(裏面土地なし)とBotでの検証結果を比較します。bot対戦では初手補正の影響によって3枚配られる確率が60%でしたが、今回の検証では55%と若干小さな値になっています。OTJ,MKMのセットでも同様に算出しましたが、どちらも3枚が約56%という数値になっていました。したがってデッキ40枚構成土地枚数17枚の時は、56%の確率で初手に土地3枚が配られます。なお初手補正がない場合は確率分布に従うため約30%となるため、56%という数値は十分に初手補正が効いていると言えます。

裏面土地なしの確率

■裏面土地ありの補正
上記の表の手札の土地枚数をグラフ化します。

17-0と18-0が裏面土地なしのデッキの確率ですが、裏面土地の有無にかかわらず初手の土地枚数の傾向は大きく変わらないように見えます。しかし裏面土地の構成割合が増えると、2枚もしくは4枚にぶれる確率が大きくなります。といっても最大の差分は8point程度です。
なので、この解析結果から
・裏面土地は実質的に土地として換算されてデッキのバランスや初手の土地枚数に評価されている(ように見える)
・裏面土地の枚数が増えると若干だが分散が大きくなる。

ということが言えます。
ということでBot対戦で検証した結果はまあまあ当たっていたと評価できます。

終わりに

ここまで読んでいただきありがとうございます。
ありがたいことに17Landsでは統計情報をわかりやすく公開してくれているため、独自でデータを解析する必要性はほとんどないと思います。
また、ブルームバロウが始まりMTGアリーナでMH3のプレミアドラフトを遊ぶ機会はほとんどなくなると思いますが、いつか裏面土地サイクルが再録される未来を信じてこの記事を書きました。
今回の取り組みや検証結果が未来の誰かの参考になれば幸いです。
(初手補正のアルゴリズムが変わらなければいいなー。)

今更ですが、本記事は17Landsが公開するをデータを用いた検証結果による考察であり、結果を保証するものでありませんのでご了承ください。
それでは!


 

この記事が気に入ったらサポートをしてみませんか?