🙇‍♂️

【ポケポケ】カイ二乗検定でカスミが不正してないかチェックしよう!

2024/12/11に公開

こんにちは!皆さんは「ポケポケ」を楽しんでいますか?
最近、通勤時間の過ごし方が読書から「ポケポケ」に変わりました。
ちなみに、私が使っているのは「カスミ」と「キングラー」デッキです。

このデッキはコイン出目にほぼ全てかかっているといっても過言ではないのですが、最近負けたときには全部「カスミのコイン、裏ばかり出ていませんか?誠に遺憾です。」とカスミのせいにして自分を責めないことで心の平穏を保っています。

この人は一体何のお話をしてるの?

何のお話かわからない方もいるでしょうから、簡単に用語の解説だけします。

用語 : ポケポケ

Pokémon Trading Card Game Pocketの略です。

用語 : カスミ

  • ポケポケに登場するカスミというカードがありまして、効果は以下です。
  • コインを1枚投げる。裏が出るまでこの試行を繰り返す。最後に、表が出た回数だけエネルギー的なものをポケモンにチャージする。

この人は何をするの?

この記事では、カスミのコイン投げの公平性を検証しようと思います。もしかしたらカスミは裏が出る確率が高く設定されているのかもしれませんし、これは検証せずにはいられません。
コイン投げが公平かどうかを検証する方法として、カイ二乗検定を使用することにします。

カイ二乗適合度検定でカスミが不正していないか確認しよう!

カイ二乗適合度検定は、観測された頻度データが特定の理論分布にどの程度一致しているかを検証する統計手法です。具体的には、今回はオンライン対戦で振ったコインの分布が、期待される幾何分布に適合しているかどうかを調べます。

カイ二乗適合度検定とは?

カスミのコイン投げで得られるエネルギーの個数が幾何分布に従うと仮定します。幾何分布は成功確率 pを持つ1パラメータの分布で、確率質量関数は以下のように定義されます。

P(X=k) = (1-p)^{k-1}p

ここでk,pは以下の通りです。

  • k:はじめて裏が出たときの試行回数
  • p:成功確率(今回では裏が成功で、確率は0.5)

期待される理論分布は幾何分布に従っているとすると、各試行回数での成功確率は以下のようになります。

X P
1 0.5
2 0.25
3 0.125
... ...
k (1-p)^{k-1}p
... ...

カイ二乗適合度検定では、次のような仮説を設定します。

  1. 帰無仮説(H_0): 観測されたデータは、指定した理論分布に適合している。
  2. 対立仮説(H_1): 観測されたデータは、指定した理論分布に適合していない。

今回の理論分布はもちろん幾何分布ですね。

カイ二乗適合度検定の中心となるのがカイ二乗統計量の計算です。この統計量は、観測データと期待データの間の差異を表し、差異が小さいほど適合性が高いことを意味します。以下にカイ二乗統計量を示します。

\chi^2 = \sum \frac{(O_i - E_i)^2}{E_i}

ここで、O_iは各カテゴリの観測値、E_iは各カテゴリの期待値です。
カイ二乗統計量は、観測値と期待値の間の差の2乗を期待値で割り、その総和を取ることで計算されます。この計算により、各カテゴリの差異が全体の適合性にどの程度影響を与えているかを評価します。

  • 差が大きい場合:カイ二乗統計量が大きくなり、観測値と期待値の間に有意な差がある可能性が高い。
  • 差が小さい場合:カイ二乗統計量が小さくなり、観測値が期待値に近いと考えられます。

検定の計算手順

  1. カテゴリの分割
    データをいくつかのカテゴリ(例: 試行回数1回、2回…)に分割します。

  2. 期待値(E_i)の計算
    幾何分布の確率式に基づいて、各カテゴリの期待値を計算します。期待値は理論確率に全体の試行数を掛けることで求められます。

  3. カイ二乗統計量の算出
    観測値と期待値を用いて、カイ二乗統計量を計算します。

  4. 自由度とp値の比較
    自由度(カテゴリ数-パラメータ数-1)を考慮し、カイ二乗分布を使ってp値を求めます。

  5. 仮説の判定
    p値が有意水準(例:5%)以下なら、帰無仮説を棄却します。
    p値が有意水準を超えるなら、帰無仮説を採択します。

カスミデータの確認

まず、オンライン対戦で収集したカスミのコインデータを確認します。カスミを使う度に表を1、裏を0として記録しました。最終的に217サンプルが得られています。

import pandas as pd 

kasumi_count = pd.read_csv('./kasumi.csv')

データのサンプルを以下に示します。

count
0 0
1 10
2 0
3 1110
4 10
... ...
212 10
213 0
214 0
215 0
216 10

各行は、1回の試行結果が連続した数値として記録されています。たとえば、「1110」は表が3回連続し、4回目に裏が出た、といった具合です。

データ変換

データは、表を1、裏を0として記録されています。しかし、この形式のままでは分析が難しいため、次の処理を行います:

  • 連続する1(表)の数を計算します。
  • 0(裏)が出るまでのコインの試投回数を新しいカラムに追加します。
# 連続する1の数を抽出
def parse_consecutive_ones(value):
    value_str = str(value)  # 数値を文字列に変換
    # 正規表現で "1" の連続を探す
    ones_groups = re.findall(r'1+', value_str)
    # 連続する1の最大数を取得、無い場合は0
    return max((len(group) for group in ones_groups), default = 0 )

# 新しい列に結果を保存
kasumi_count['consecutive_ones'] = kasumi_count['count'].apply(parse_consecutive_ones)
kasumi_count['throws_until_tails'] = kasumi_count['consecutive_ones'] + 1 

先頭から連続する1(表)の個数、0(裏)が出るまでの試投回数(throws_until_tails)を追加しました。このthrows_until_tailsが幾何分布に従うかを検定するのが今回の目標です。

count consecutive_ones throws_until_tails
0 0 0 1
1 10 1 2
2 0 0 1
3 1110 3 4
4 10 1 2
... ... ... ...
212 10 1 2
213 0 0 1
214 0 0 1
215 0 0 1
216 10 1 2

データの可視化

収集したデータから得られた試投回数(throws_until_tails)を可視化して、データの特徴を確認します。今回のサンプル数は217個と少ないため、頻度が少ないカテゴリがいくつか存在することが予想されます。まずはデータの統計量を確認し、その後ヒストグラムで分布を視覚化します。

throws_until_tails = kasumi_count['throws_until_tails'] 

# データの統計量を計算
mean_value = np.mean(throws_until_tails)
variance_value = np.var(throws_until_tails)
max_value = np.max(throws_until_tails)
min_value = np.min(throws_until_tails)

print(f"平均試投回数: {mean_value}")
print(f"試投回数の分散: {variance_value}")
print(f"最大試行回数: {max_value}")
print(f"最小試行回数: {min_value}")

# ヒストグラムをプロット
plt.figure(figsize=(10, 6))
plt.hist(throws_until_tails, bins=range(1, max_value + 2), align='left', rwidth=0.8, color='skyblue', edgecolor='black')
plt.title("試投回数のヒストグラム",fontsize=14)
plt.xlabel("裏が出るまでの試投回数", fontsize=12)
plt.ylabel("頻度",fontsize=12)
plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.show()

試投回数の中心傾向やデータのばらつき具合が確認できます。特に分散が平均よりも大きい点は、試投回数に一定のばらつきが存在することを示唆しているのかもしれません。

平均試投回数: 2.0506912442396312
試投回数の分散: 2.315402747987853
最大試行回数: 11
最小試行回数: 1

このヒストグラムから、試投回数が短い回数(1~3回程度)に集中していることが分かります。一方で、回数が6回以上になる頻度は非常に少なく、最大で11回でした。
また、適合度検定では、頻度が5個以下のカテゴリがあると結果の信頼性が低下する可能性があります。しかし、今回は試行回数が限られているため、このまま進めます。また、頻度が少ないカテゴリを結合するなどの措置も取らないことにします。

幾何分布との形状比較

観測データと期待される幾何分布の形状を比較して、カスミのコイン投げデータが理論値とどの程度一致しているかを確認します。今回、幾何分布のパラメータは、コインの裏表が等確率であることを仮定し、成功確率p=0.5を採用しました。

# 幾何分布に基づく期待値を計算(成功確率 p = 0.5)
p = 0.5
expected = [(1 - p) ** (k - 1) * p for k in range(1, max_value + 1)]

# 観測回数を計算
observed = [throws_until_tails.tolist().count(i) for i in range(1, max_value + 1)]

# 正規化して相対頻度を計算
observed_normalized = np.array(observed) / sum(observed)

# 観測値と期待値を表示
print("Observed :", observed_normalized)
print("Expected :", expected)

# x軸の範囲(試行回数)
x = range(1, max_value + 1)

# グラフを描画
plt.figure(figsize=(10, 6))
plt.bar(x, observed_normalized, alpha=0.7, label="観測値(Normalized)", color="skyblue", edgecolor="black")
plt.plot(x, expected, label="期待値", color="red", marker="o", linestyle="--")
plt.title("観測値 vs 期待値", fontsize=14)
plt.xlabel("裏が出るまでの試投回数", fontsize=12)
plt.ylabel("Probability", fontsize=12)
plt.xticks(x)
plt.grid(axis="y", linestyle="--", alpha=0.7)
plt.legend(fontsize=12)
plt.tight_layout()
plt.show()

カスミが異常なことを証明したいのですが、なんか先行きが怪しいですね...。いえ、まだ検定結果を見るまで分かりませんからね。

検定の実施

適合度検定を実施します。
以下のコードでは、幾何分布に基づく期待値を観測データに合わせてスケール調整し、scipy.stats.chisquare関数を用いてカイ二乗統計量とp値を算出しました。

import scipy.stats as stats

# 幾何分布に基づく期待値(頻度ベース)を計算
p = 0.5
expected = [(1 - p) ** (k - 1) * p for k in range(1, max_value + 1)]

# 観測頻度の合計にスケール
expected_frequencies = np.array(expected) * sum(observed) 
expected_frequencies *= sum(observed) / sum(expected_frequencies)

# カイ二乗検定の実行
chi2_stat, p_value = stats.chisquare(observed, expected_frequencies)

# 結果を表示
print(f"Chi-squared statistic: {chi2_stat}")
print(f"P-value: {p_value}")

カイ二乗統計量とp値の結果は以下のようになりました。

Chi-squared statistic: 9.783221126152075
P-value: 0.459713615076497
  • カイ二乗統計量 : 9.78
    この値は、観測値と期待値の間のずれを定量化した指標です。値が大きいほど、観測データが理論分布(幾何分布)から外れていることを示します。
    ただし、カイ二乗統計量だけではズレの大小を判断できないため、対応する自由度(degrees of freedom)を考慮して臨界値とp-値を計算します。

  • 自由度(Degrees of Freedom):
    自由度は、比較対象となるカテゴリ数から推定パラメータの数を引いた値です。
    今回の検定では、理論分布として幾何分布を仮定し、成功確率p=0.5を事前に固定しました。そのため、観測データを用いてパラメータを推定する必要はなく、推定パラメータ数を引く必要がありません。
    そのため、今回の場合、観測カテゴリ数が11、推定パラメータ数が0(幾何分布のp=0.5は仮定済み)であるため、自由度はdf=11-1=10です。
    自由度10で有意水準0.05に対応する臨界値はカイ二分布表より18.31です。カイ二乗統計量と、臨界値を比較すると、カイ二乗統計量が下回っており、帰無仮説を棄却することができません。

  • p-値(P-value): 0.459
    この値は、帰無仮説が正しい場合に、現在のカイ二乗統計量(またはそれ以上の値)が偶然得られる確率を示します。今回のp-値は0.459であり、約45.9%の確率でこの程度の観測値のずれが偶然に発生すると考えられます。p-値の観点からも、カスミのコイン投げは確率p=0.5とした幾何分布から外れているとは言えなさそうです。

結論とまとめ

オンライン対戦で収集したカスミのデータを基に、コインの結果に偏りがあるかをカイ二乗適合度検定を用いて分析しました。
その結果、カスミのコイン投げには統計的に偏りがある、とは言えませんでした。体感「0以外出ねーぞ!(台パン)」って感じだったのですが、人間の思い込みって怖いですな。

しかし皆さんもぜひ試してみてください。あなたのカスミは異様に表を出す子かもしれませんよ。

Goals Tech Blog

Discussion