シミュレーション工学5
Dublin Core
Title
Creator
Date Created
Rights
CC BY-NC 4.0 - 非営利目的のみ許可
note Item Type Metadata
note
つり銭問題のシミュレーション
学習目標
- シミュレーション手法の理解と実践
- 確率論的思考の習得
- 実問題の数学的モデル化
- 統計的分析手法の応用
- プログラミングによる数値計算
前提知識
- 基本的な確率の概念
- Pythonプログラミングの基礎
- 統計の基本概念(平均、分散、分布)
問題設定
変数の定義
- x: ある時点での1000円札の枚数
- y: お釣りの必要枚数
- n: メンバー数(15人)
支払いパターン
- 1000円札3枚で支払い: x → x + 3
- 10000円札1枚で支払い: x → x - 7(お釣りとして1000円札7枚必要)
- 確率: 各パターン50%の確率
お釣り必要枚数の計算
- y = 0 (min x ≥ 0): 最小値が0以上の場合、お釣りの準備は不要
- y = |min x| (min x < 0): 最小値がマイナスの場合、マイナス分だけ必要
シミュレーションの流れ
フローチャート
開始
↓
x = 0, min_x = 0
↓
部員i (i=1 to 15)
↓
ランダム選択 (50%確率)
↓
┌─────────────────┬─────────────────┐
│ 1000円札3枚 │ 10000円札1枚 │
│ x = x + 3 │ x = x - 7 │
└─────────────────┴─────────────────┘
↓
min_x = min(min_x, x)
↓
i < 15? → Yes → 次の部員
↓ No
y = max(0, -min_x)
↓
結果を記録
↓
終了
ステップ詳細
- 初期化: お釣りの枚数をx=0で初期化
- 支払い決定: 50%の確率で1000円札3枚か10000円札1枚を決定
- 状態更新: 支払い方法に応じてxを更新:
- 1000円札3枚: x → x + 3
- 10000円札1枚: x → x - 7
- 最小値記録: min_x = min(min_x, x)
- 繰り返し: 15回繰り返す
- 結果計算: xの最小値から必要なお釣りの枚数を決定
Python実装例
実行方法
- Pythonがインストールされていることを確認
- 以下のコードをtsurisen.pyとして保存
- コマンドプロンプトでpython tsurisen.pyを実行
import random
def tsurisen_simulation(trials=10000):
"""
つり銭問題のシミュレーション
Args:
trials (int): シミュレーション回数(デフォルト: 10000回)
"""
MEMBER_N = 15 # 部員数
result = [] # 結果を格納するリスト
# 指定回数だけシミュレーションを実行
for _ in range(trials):
x = 0 # お釣りとして持っている1000円札の枚数
min_x = 0 # xの最小値を記録
# 15人の部員が順番に支払う
for _ in range(MEMBER_N):
if random.random() < 0.5:
# 50%の確率で1000円札3枚で支払う
x += 3
else:
# 50%の確率で10000円札1枚で支払う
x -= 7
# 現在のxの最小値を更新
min_x = min(min_x, x)
# 必要なお釣り枚数を計算
# min_x が 0以上ならお釣り不要, 0未満ならその絶対値だけ必要
y = 0 if min_x >= 0 else abs(min_x)
result.append(y)
# 結果を表示
print("=== つり銭問題シミュレーション結果 ===")
print(f"シミュレーション回数: {trials:,}回")
print(f"必要なお釣りの枚数の平均: {sum(result)/len(result):.2f}枚")
print(f"最小必要お釣り枚数: {min(result)}枚")
print(f"最大必要お釣り枚数: {max(result)}枚")
print(f"お釣り不要(0枚)の確率: {result.count(0)/len(result)*100:.1f}%")
# 分布を表示
from collections import Counter
distribution = Counter(result)
print("\n=== お釣り枚数の分布 ===")
for count in sorted(distribution.keys()):
print(f"{count}枚: {distribution[count]:,}回 ({distribution[count]/len(result)*100:.1f}%)")
if __name__ == "__main__":
tsurisen_simulation()
実装の説明
このコードは、部員15人がランダムに1000円札3枚または10000円札1枚で会費を払う場合について1万回試行し、必要な1000円札のお釣り枚数が最小で何枚必要かを統計的に調べます。
出力される統計情報:
- 必要なお釣りの枚数の平均値
- 最小必要お釣り枚数(最頻値)
- 最大必要お釣り枚数
- お釣り不要(0枚)の確率
実用的な対策とアドバイス
幹事向けの準備指針
- 事前準備: 平均的な必要枚数分の1000円札を用意
- リスク管理: 最大必要枚数分の余裕を持って準備
- 効率的な集金方法:
- 事前に支払い方法を確認
- 小額紙幣での支払いを推奨
- 電子マネー併用を検討
シミュレーション結果の活用
- 確率的な準備: 95%の確率でカバーできる枚数を計算
- コスト分析: お釣り準備のコストとリスクのバランス
- 代替案の検討: 支払い方法の変更による効果測定
モデル化の確認
1. モデル化の目的を明らかにする
対象の選択
- シミュレーション対象: 部の会費を集める際のつり銭問題
目的の決定
- 目的: 必要なつり銭の枚数を調べる
2. モデルの構造を決定する
現実問題の抽象化
必要な構造情報:
- 会費の支払い方法
- お釣りの支払い方法
- お釣りの枚数
- お札や小銭の種類
- サークルの人数
3. 分析手法の選択
- プログラム(Python)
- Excel
- 専用アプリ
4. 仮定・条件の設定
シミュレーション条件
- 部員数: 15人
- 支払い方法: 一人ずつ幹事に支払う
- 支払いパターン:
- 1000円札3枚で支払う
- 10000円札1枚で支払う
- お釣り: 10000円札で支払われた場合、1000円札7枚をお釣りとして支払う
5. モデルの数式表現
数学的モデル
- 状態変数: xt = 時点tでの1000円札の枚数
- 確率変数: Zi = 部員iの支払い方法
- P(Zi = 1) = 0.5 (1000円札3枚)
- P(Zi = -1) = 0.5 (10000円札1枚)
状態遷移式
xt+1 = xt + 3Zi if Zi = 1
xt+1 = xt - 7 if Zi = -1
目的関数
y = max(0, -mint=115 xt)
期待値の計算
- 1000円札3枚の期待増加: 3 × 0.5 = 1.5枚
- 10000円札1枚の期待減少: -7 × 0.5 = -3.5枚
- 1人あたりの期待変化: 1.5 - 3.5 = -2枚
- 15人全体の期待変化: -2 × 15 = -30枚
理論的考察
この問題はランダムウォークの一種で、負の値に到達する確率を求める問題として定式化できます。
高度な分析と検証
統計的検証
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
def advanced_analysis():
"""高度な統計分析"""
# シミュレーション実行
results = []
for _ in range(100000):
x, min_x = 0, 0
for _ in range(15):
if np.random.random() < 0.5:
x += 3
else:
x -= 7
min_x = min(min_x, x)
results.append(0 if min_x >= 0 else abs(min_x))
# 統計量の計算
mean_val = np.mean(results)
std_val = np.std(results)
median_val = np.median(results)
# 信頼区間の計算
confidence_interval = stats.norm.interval(0.95, loc=mean_val, scale=std_val/np.sqrt(len(results)))
print(f"平均: {mean_val:.3f}")
print(f"標準偏差: {std_val:.3f}")
print(f"中央値: {median_val:.3f}")
print(f"95%信頼区間: [{confidence_interval[0]:.3f}, {confidence_interval[1]:.3f}]")
# 分布の可視化
plt.hist(results, bins=20, alpha=0.7, density=True)
plt.xlabel('必要なお釣り枚数')
plt.ylabel('確率密度')
plt.title('つり銭必要枚数の分布')
plt.show()
if __name__ == "__main__":
advanced_analysis()
感度分析
- 部員数の影響: 10人、15人、20人での比較
- 確率の影響: 支払い方法の確率を変更した場合の効果
- 会費額の影響: 異なる会費額でのシミュレーション
最適化問題としての定式化
min 準備する1000円札の枚数
s.t. P(お釣り不足) ≤ α
演習問題と実践課題
基礎演習
- 手計算による小規模シミュレーション
- 部員数5人で手計算でシミュレーション
- 支払いパターン: 1000円札3枚 vs 10000円札1枚
- 各パターンの確率を計算
- パラメータ変更実験
- 部員数を10人、20人に変更して結果を比較
- 支払い確率を30%:70%に変更して効果を確認
応用課題
- 現実的な条件でのシミュレーション
- 会費額を5000円に変更
- 支払い方法を3種類に拡張(1000円札5枚、5000円札1枚、10000円札1枚)
- 確率分布を非対称にする
- コスト最適化問題
- お釣り準備のコストを考慮
- 不足時のペナルティコストを設定
- 最適な準備枚数を数値的に求める
高度な課題
- 動的シミュレーション
- 部員が順番に来る時間間隔をランダム化
- リアルタイムでのお釣り管理
- 銀行への換金回数も考慮
- 多目的最適化
- コスト最小化とリスク最小化のトレードオフ
- パレート最適解の探索
モデルの限界と批判的考察
現実との乖離点
- 理想化された仮定
- 支払い方法が2種類のみ(現実は多様)
- 確率が固定(個人差を無視)
- 支払い順序がランダム(実際はパターンがある)
- 考慮されていない要因
- 部員の支払い能力の違い
- 季節性やイベントの影響
- 電子マネーやクレジットカードの普及
- 銀行の営業時間制約
- 統計的仮定の問題
- 独立性の仮定(部員間の影響を無視)
- 正規分布の仮定(実際の分布は不明)
- 大数の法則の適用限界
モデル改善の方向性
- より現実的な確率分布
- ベータ分布やポアソン分布の使用
- 個人差を考慮した混合分布
- 動的要素の導入
- 時間経過による確率変化
- 学習効果や慣れの影響
- 多変量分析
- 部員の属性(年齢、収入)との相関
- 外部要因(経済状況、イベント)の影響
検証方法の限界
- シミュレーション回数の妥当性
- 初期条件の敏感性
- パラメータ推定の不確実性
国際的視点と応用
多国通貨での応用
この問題は各国の通貨制度に応用可能です:
アメリカ(USD)
- 会費: $30
- 支払い方法: $1札30枚 vs $50札1枚
- お釣り: $50札で支払い時、$1札20枚が必要
ヨーロッパ(EUR)
- 会費: €25
- 支払い方法: €5札5枚 vs €50札1枚
- お釣り: €50札で支払い時、€5札5枚が必要
文化的要因の考慮
- 支払い習慣の違い
- 日本: 現金重視
- 北欧: 電子決済普及
- 発展途上国: 小額紙幣多用
- 社会的要因
- 年齢層による支払い方法の違い
- 経済状況による影響
- 教育レベルとの相関
英語版サマリー
English Summary
""" Change Management Simulation Problem: Determine optimal amount of small bills to prepare for collecting membership fees from 15 members. Payment Methods: - 3 × 1000-yen bills (increases small bills by 3) - 1 × 10000-yen bill (requires 7 small bills as change) Objective: Minimize preparation while avoiding shortage """
Collection
Citation
unjuno, “シミュレーション工学5,” unjuno'sResearchLibrary, accessed October 8, 2026, https://archive.unjuno.org/items/show/109.
コメント