アドカレも折り返し地点。
負けそうになっているので先日過去問道場で見かけた『モンテカルロ法』を使って見ることにしました。
モンテカルロ法とは?
”モンテカルロ法”とは、乱数を使って同じ実験を大量に繰り返し、サンプリングの結果の分布から、答えを推定する手法ということでした。
『モンテカルロ法』というと名前が洒落ており内容が推測しにくいですが、元々日本語では『統計的標本抽出法』とも呼ばれていたという記載がありました。(能澤正雄『科学史のこぼれ話(その7)』 --by原子力データセンター)
そしてその手法は第二次世界大戦中(特に中性子、核兵器開発のような体型内の物質校正や密度が空間的時間的に急激に変化する事柄に対する計算方法としての文脈として)に生まれたそうです。
モンテカルロ法は、不確実な状況下での意思決定を改善するために、第二次世界大戦中にJohn von NeumannとStanislaw Ulamによって考案されました。
『モンテカルロ・シミュレーションとは』 --byIBM
『モンテカルロ法』という名前になったきっかけ
きっかけとしては
- スタニスワフ・ウラムさん(ポーランドの数学者)
- 休憩時間にソリティアをしていたところ、52枚のカードにおいてソリティアが完成する確率に思い悩む→
- 確率で解こうとしたらは約8×10の67乗通りという途方もない組み合わせになることに悩む→
- ”数撃ちゃ当たる作戦”に。
- 『これは高速コンピュータの新時代の幕開け』と知り、水素爆弾の開発に役立つことを思いつく”Hitting the Jackpot: The Birth of the Monte Carlo Method
” --by LosAlamosNationalLaboratory→ - それを手紙でノイマンさんに伝える→
- ジョン・フォン・ノイマンさん
- ロスアラモス研究所(第二次世界大戦中(1943年)に原子爆弾の開発を目的としてニューメキシコ州ロスアラモスに創設された『ロスアラモス国立研究所』 --by Wikipedia)の研究者に伝える→
- メトロポリスさん、この手法を『モンテカルロ法』と名付ける
- 名付けの理由①:確率的な存在がヨーロッパのカジノ『モンテカルロ』を彷彿とさせるから
- 名付けの理由②:ウランさんのおじさんが“just had to go to Monte Carlo(モンテカルロ行かなきゃ)”といって金を借りていたエピソードも影響した
ウラムは、ENIAC を用いたら、統計的標本抽出法(後に、モンテカルロ法と呼ばれるようになった)による熱核反応の臨界質量の計算が容易にできると考えノイマンに手紙で伝えた。
ノイマンは、この方法をロスアラモスの研究者らに伝えた。
その中には、メトロポリスがいた。
メトロポリスは、現在、我々が物質科学で利用しているモンテカルロ法の創始者になった。
三上益弘『連載 「分子シミュレーション入門 15 輸送係数の計算方法」』--byJ-Stage
ウラムさんは後にこう述べたそうです。
“It is still an unending source of surprise for me to see how a few scribbles on a blackboard or on a sheet of paper could change the course of human affairs.”
「黒板や一枚の紙に少し落書きしただけで、人類の運命がこれほどまでに変わるとは、今でも驚きの連続です。」
”Hitting the Jackpot: The Birth of the Monte Carlo Method
” --by LosAlamosNationalLaboratory
(【小さく余計な個人的感想】
「モンテカルロ」という華やかな名前や、数学的に洗練されたイメージとは裏腹に、この手法が最初に使われたのは戦時中の効率化(:“いかに効率よく破壊するか”)のためだったことを知り、科学技術に付随する倫理的な問題に複雑な思いを抱きました。
(科学技術is歴史だ...))
アドカレを完走できるかモンテカルロ法を使ってシミュレーション
たったの25日間の人間のシミュレーションに大きな意味はありませんが、『モンテカルロ法』の醍醐味を理解するためにPythonにてシミュレーションしてみました。
結果は、
- 79.8%の確率で『あと一歩』
- 17.7%の確率で『完走』
でした。
人間生活にとってマイナスなイベントが多すぎるため、つい重みの設定をマイナス寄りにしたくなり、閾値や設定が限界を突破しかけたため、調整が難儀でした。
軽い人生ゲームのようにできて、楽しめると感じました。
=========
2025/12/12 22:11:35
No.8682893さん
=========
計算方法:モンテカルロ法
=========
基本情報技術者試験にもたまーに出てくる『モンテカルロ法』とは、
ランダムな乱数を繰り返し実行することによって、
結果を算出する計算アルゴリズムです♪
この結果は、モンテカルロ法を用いて算出した
あなたが25日間それなりの質を維持して
アドベントカレンダーを完走できる確率です。
===結果===
【ほぼ確】 あと一歩 : 79.80%
【大勝利】 完走 : 17.77%
【本命】 無双 : 2.43%
備考:「モンテカルロ」地区はモナコ公国北東部、モナコ湾の北岸に位置する地区である、
また、イタリア共和国トスカーナ州ルッカ県にある、人口約4,400人の基礎自治体も
「モンテカルロ」という名前だそうです。
またのご来店、お待ちしてます♪
良いモンテカルロを♪
========================================
コード全文
コード全文
import random
from datetime import datetime
# 重み付きランダム選択関数
def pick(weighted_dict):
r = random.random()
cumulative = 0
for value, w in weighted_dict.items():
cumulative += w
if r < cumulative:
return value
return list(weighted_dict.keys())[-1]
# 1日のスコア
def simulate_one_day():
score = 0
# (12月の)天気 (晴れたら快調)
score += pick({
+4: 0.10, +2: 0.20, 0: 0.40, -1: 0.20, -2: 0.10,
})
# 起床 (出社勢の悩み:5時、6時、7時、7時半)
score += pick({
+3: 0.20, +1: 0.40, 0: 0.20, -2: 0.20,
})
# 電車の不快度指数(通常、激混み、遅延、もみくちゃ)
score += pick({
+2: 0.15, 0: 0.55, -2: 0.25, -4: 0.05,
})
# 睡眠度(快眠、通常、アドレナリン、悪夢)
score += pick({
+3: 0.25, +1: 0.35, -1: 0.25, -3: 0.15,
})
# 体調(絶好調、好調、不調、絶不調)
score += pick({
+3: 0.20, 0: 0.50, -2: 0.20, -4: 0.10,
})
# 残業時間(0時間、1時間、2時間、3時間)
score += pick({
0: 0.60, -1: 0.30, -3: 0.08, -5: 0.02,
})
# リーダーの毒舌の調子(不調、普通、好調、絶好調)
score += pick({
+1: 0.10, 0: 0.50, -2: 0.30, -4: 0.10,
})
# 野良猫に遭遇(遭遇、遭遇しない)
score += pick({
+4: 0.02, 0: 0.98,
})
# カラスにフンを落とされる(落とされない、落とされる)
score += pick({
0: 0.98, -5: 0.02,
})
return score
# 25日間の合計
def simulate_25_days():
total = 0
for _ in range(25):
total += simulate_one_day()
return total
# 結果
def categorize(total):
if total >= 25:
return "無双"
elif total >= 0:
return "完走"
elif total >= -110:
return "あと一歩"
elif total >= -400:
return "挫折"
elif total >= -500:
return "虚無"
else:
return "逃走"
# モンテカルロシミュレーションの実行
def monte_carlo(n=10000):
stats = {}
for _ in range(n):
total = simulate_25_days()
cat = categorize(total)
stats[cat] = stats.get(cat, 0) + 1
return stats
# 結果
def print_summary(stats, N):
# ソート
ordered = sorted(stats.items(), key=lambda x: x[1], reverse=True)
# レシート
now = datetime.now().strftime("%Y/%m/%d %H:%M:%S")
rand_no = f"No.{random.randint(0, 9999999):07d}さん"
labels = ["【ほぼ確】", "【大勝利】", "【本命】", "【大穴】", "【末脚不発】", "【気配なし】"]
print("=========\n")
print(f"{now}")
print(f"{rand_no}")
print("=========")
print("計算方法:モンテカルロ法")
print("=========")
print("基本情報技術者試験にもたまーに出てくる『モンテカルロ法』とは、")
print("ランダムな乱数を繰り返し実行することによって、")
print("結果を算出する計算アルゴリズムです♪\n")
print("\n")
print("この結果は、モンテカルロ法を用いて算出した")
print("あなたが25日間それなりの質を維持して")
print("アドベントカレンダーを完走できる確率です。\n")
print("===結果===\n")
# 各カテゴリの確率を表示
for i, (name, count) in enumerate(ordered):
p = count / N * 100
label = labels[i] if i < len(labels) else ""
print(f"{label}\t{name:<6} : {p:6.2f}%")
print("\n\n")
print("備考:「モンテカルロ」地区はモナコ公国北東部、モナコ湾の北岸に位置する地区である、")
print("また、イタリア共和国トスカーナ州ルッカ県にある、人口約4,400人の基礎自治体も")
print("「モンテカルロ」という名前だそうです。")
print("")
print("またのご来店、お待ちしてます♪")
print("良いモンテカルロを♪")
print("========================================")
if __name__ == "__main__":
N = 10000
stats = monte_carlo(N)
print_summary(stats, N)
# ※生成AI利用について
# ネタや確率設定は自作ですが、モンテカルロ法の実装や整形には、生成AIのサポートを受けました。
参考
