「第1476回 MEGA BIG」シミュレーション
このツイートに感銘を受けたのでシミュレーションしてみた。
10,000回×15,710,882口をランダム生成してみて、全体の結果と245,000口を購入した場合の収支です。
なお、2-6等は別記事の通り300円なる想定です。
1等当選金の統計:
1%値: 2417.13万円
5%値: 2508.44万円
10%値: 2566.13万円
15%値: 2606.17万円
20%値: 2637.11万円
25%値: 2668.47万円
30%値: 2690.33万円
35%値: 2712.19万円
40%値: 2734.50万円
45%値: 2757.13万円
50%値: 2780.09万円
55%値: 2803.36万円
60%値: 2827.04万円
65%値: 2851.26万円
70%値: 2875.84万円
75%値: 2901.15万円
80%値: 2939.12万円
85%値: 2978.57万円
90%値: 3032.58万円
95%値: 3117.57万円
99%値: 3270.33万円
平均: 2793.34万円
1等当選口数の統計:
1%値: 204.00口
5%値: 214.00口
10%値: 220.00口
15%値: 224.00口
20%値: 227.00口
25%値: 230.00口
30%値: 232.00口
35%値: 234.00口
40%値: 236.00口
45%値: 238.00口
50%値: 240.00口
55%値: 242.00口
60%値: 244.00口
65%値: 246.00口
70%値: 248.00口
75%値: 250.00口
80%値: 253.00口
85%値: 256.00口
90%値: 260.00口
95%値: 266.00口
99%値: 276.00口
平均: 239.86口
還元率の統計:
1%値: 173.70%
5%値: 173.70%
10%値: 173.70%
15%値: 173.70%
20%値: 173.70%
25%値: 173.70%
30%値: 173.70%
35%値: 173.70%
40%値: 173.70%
45%値: 173.70%
50%値: 173.70%
55%値: 173.70%
60%値: 173.70%
65%値: 173.70%
70%値: 173.70%
75%値: 173.70%
80%値: 173.70%
85%値: 173.70%
90%値: 173.70%
95%値: 173.70%
99%値: 173.70%
平均: 173.70%
245,000口購入時の収支の統計:
1%値: -4988.85万円
5%値: -2261.77万円
10%値: -1967.79万円
15%値: 353.42万円
20%値: 625.04万円
25%値: 945.33万円
30%値: 2738.32万円
35%値: 3141.79万円
40%値: 3489.92万円
45%値: 3919.95万円
50%値: 5158.46万円
55%値: 5808.21万円
60%値: 6281.27万円
65%値: 6884.42万円
70%値: 8101.55万円
75%値: 8911.53万円
80%値: 9774.29万円
85%値: 11151.52万円
90%値: 12638.87万円
95%値: 15151.72万円
99%値: 20020.82万円
平均: 5448.32万円
7350万円&今回のシミュレーションの場合、下振れ11.9%を回避できれば儲かりそうでした
幸せになって欲しい!!
>>> np.quantile(merged_results[3], 11.8/100)
-9.781935999999309
>>> np.quantile(merged_results[3], 11.9/100)
15.788008000000014
コードも置いておきます。
※メモリもりもりM2 Ultra(192GB)のコードなので適宜調整ください
#!python3
import gc
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import font_manager
# 複数回のシミュレーション結果をマージしてヒストグラムを作成
n_iterations = 20 # 500回のシミュレーションを20回繰り返す
n_simulate_per_iteration = 500 # メモリ192GB想定、適宜調整を
results = []
# プロット設定
plt.figure(figsize=(15, 20))
font_path = '/System/Library/Fonts/ヒラギノ角ゴシック W3.ttc'
font_prop = font_manager.FontProperties(fname=font_path)
plt.rcParams['font.family'] = font_prop.get_name()
titles = ['1等当選金の分布', '1等当選口数の分布', '還元率の分布', '245,000口購入時の収支の分布']
xlabels = ['1等当選金額(万円)', '1等当選口数', '還元率(%)', '収支(万円)']
def run_simulation(n_simulate):
# シミュレーション設定
YEN_CARRYOVER = 5_830_122_720 # キャリーオーバー
YEN_SELL = 4_713_264_600 # 売上
N_TICKET = 15_710_882 # 総投票口数
N_GAME = 8 # 対象ゲーム数(第1476回は4試合中止で8試合)
N_BUY_SIMULATE = 245_000 # シミュレーションでの購入口数
# N_SIMULATE回分のランダム投票を作成
np_vote = np.random.randint(low=0, high=3+1, size=n_simulate*N_TICKET*N_GAME, dtype=np.uint8).reshape(n_simulate, N_TICKET, N_GAME)
# 結果が正解(0)のゲーム数をカウント
np_count_matched = (np_vote == 0).sum(axis=2)
# 1-6等の当選口数をカウント
np_count_prize = np.array([(np_count_matched == i).sum(axis=1) for i in range(N_GAME, N_GAME-6, -1)]).T
# 1等の払戻金額を計算
np_prize_1st = (int(YEN_CARRYOVER + YEN_SELL * 0.5) - np_count_prize[:, 1:].sum(axis=1) * 300) / np_count_prize[:, 0] // 10 * 10
# 還元率を計算
np_odds = (np_prize_1st * np_count_prize[:, 0] + 300 * np_count_prize[:, 1:].sum(axis=1)) / YEN_SELL * 100
# N_BUY口購入した場合の収支計算
np_count_matched_simulate = np_count_matched[:, :N_BUY_SIMULATE]
np_count_prize_simulate = np.array([(np_count_matched_simulate == i).sum(axis=1) for i in range(N_GAME, N_GAME-6, -1)]).T
np_profit_simulate = np_prize_1st * np_count_prize_simulate[:, 0] + 300 * np_count_prize_simulate[:, 1:].sum(axis=1) - N_BUY_SIMULATE * 300
np_profit_simulate_man = np_profit_simulate / 10000
# 単位変換: 1等当選金を万円に
np_prize_1st_man = np_prize_1st / 10000
return np_prize_1st_man, np_count_prize[:, 0], np_odds, np_profit_simulate_man
for i in range(n_iterations):
print(f"Running simulation {i+1}/{n_iterations}")
np.random.seed(i) # 各イテレーションで異なるシードを使用
results.append(run_simulation(n_simulate_per_iteration))
gc.collect() # メモリを解放
# 結果をマージ
merged_results = [np.concatenate([r[i] for r in results]) for i in range(4)]
#プロット
for i, (data, title, xlabel) in enumerate(zip(merged_results, titles, xlabels), 1):
plt.subplot(4, 1, i)
plt.hist(data, bins=50, edgecolor='black', weights=np.ones_like(data)/len(data)*100)
plt.title(title)
plt.xlabel(xlabel)
plt.ylabel('頻度 (%)')
plt.grid(True, linestyle='--', alpha=0.7)
if i == 3: # 還元率のヒストグラム
x_min, x_max = data.min(), data.max()
plt.xlim(int(x_min * 0.99), int(x_max * 1.01))
plt.xticks(np.linspace(int(x_min * 0.99), int(x_max * 1.01), 10))
plt.tight_layout()
plt.savefig('toto_simulation_histograms_merged.png', dpi=300, bbox_inches='tight')
plt.close()
print("マージされたヒストグラムが 'toto_simulation_histograms_merged.png' として保存されました。")
# 統計情報の出力
def print_stats(data, name, unit):
percentiles = [1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 99]
print(f"{name}の統計:")
for p in percentiles:
print(f"{p:3d}%値: {np.percentile(data, p):.2f}{unit}")
print(f" 平均: {np.mean(data):.2f}{unit}")
for data, name, unit in zip(merged_results, ["1等当選金", "1等当選口数", "還元率", "245,000口購入時の収支"], ["万円", "口", "%", "万円"]):
print_stats(data, name, unit)