ブルウィップ効果は、最終需要の小さな変動が上流に行くほど発注量の大きな振れとして増幅される現象です。本記事では、Python による 4 段階のシミュレーションを通じて、工場段階の発注振れが最終需要の 46.0 倍に達する様子を数値で確認します。
ブルウィップ効果とは
ブルウィップ効果とは、最終需要の小さな変動が、サプライチェーンの上流に行くほど発注量の大きな振れとして増幅される現象です。小売店が受けた注文のわずかな変化は、卸や工場に届くまでに予測の連鎖を通じて拡大し、在庫の過剰や不足を招きます。この現象は、ビールゲームというシミュレーションを通じて広く知られています。ゲームでは、各段階が自分の受注しか見えず、最終需要を直接把握できないという情報の遅れが、発注の不安定さを生む要因として指摘されています。
なぜ増幅が起きるのか
ブルウィップ効果の増幅は、各段階の自然な行動の連鎖から生じます。各段階は、自分の受注しか見えず、最終需要を直接知りません。この情報の遅れにより、予測の更新が上流へ伝わるたびに歪みが生じます。
具体的には、各段階が受注を見て予測を更新し、リードタイム分の在庫目標との差を発注するという仕組みです。リードタイムが長いほど目標在庫が大きくなり、予測の変化が発注量の変化に倍加されます。このシミュレーションでは、リードタイムを2週、段階を4段階として設定しています(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
なお、本記事で示す計算結果は、乱数で生成した架空のサンプルデータによるものです。実際の業務データとは異なりますが、増幅の構造を理解するための参考としてお読みください。
Pythonで 4 段階のサプライチェーンを動かす
ここでは、Python で 4 段階のサプライチェーンを再現します。各段階は、自分の受注のみを見て在庫を管理します。最終需要を直接知ることはできません。この情報の非対称性が、後述する増幅の起点になります。
まず、各段階の計算ロジックを定義します。
小売 → 卸 → 二次卸 → 工場の 4 段階で、各段階が受注を予測して発注する仕組み
def simulate_chain(demand, n_stages=4, lead_time=2, alpha=0.3, safety_weeks=1):
"""小売 → 卸 → 二次卸 → 工場 の n_stages 段階を週ごとに動かす。
各段階は、受注量を指数平滑(係数 alpha)で予測し、
目標在庫 = 予測 × (リードタイム + 安全週数) と在庫ポジション(手持ち + 発注残)の差を発注する。
下流の発注が、次の週の上流の受注になる。戻り値は段階ごとの発注量の時系列。
"""
weeks = len(demand)
orders = [[0.0] * weeks for _ in range(n_stages)]
forecast = [float(demand[0])] * n_stages
position = [float(demand[0]) * (lead_time + safety_weeks)] * n_stages
for t in range(weeks):
incoming = float(demand[t]) # 小売が受ける最終需要
for s in range(n_stages):
forecast[s] = alpha * incoming + (1 - alpha) * forecast[s]
target = forecast[s] * (lead_time + safety_weeks)
position[s] -= incoming # 受注分を出荷
order = max(0.0, target - position[s]) # 目標との差を発注(マイナスなら発注しない)
orders[s][t] = order
position[s] += order # 発注残として在庫ポジションに加える
incoming = order # 上流の受注になる
return ordersは、指数平滑を用いて需要予測を更新し、リードタイムと安全在庫期間を加味した目標在庫を算出します。現在の在庫ポジションと目標在庫の差から、発注量を決定します。平滑化係数 α は 0.3 に設定しています。この値は、予測が受注の変化にどの程度追従するかを制御します。
次に、シミュレーションを実行します。
需要が途中で増える 36 週間を走らせ、段階ごとの発注量の振れを比べる
import numpy as np
rng = np.random.default_rng(3) # 固定シード(毎回同じ架空データ)
weeks, step_week = 36, 8
demand = [4 if t < step_week else 8 for t in range(weeks)] # 8 週目から需要が倍になる
demand = [max(0, d + rng.normal(0, 0.5)) for d in demand] # 小さなばらつき
orders = simulate_chain(demand, n_stages=4, lead_time=2, alpha=0.3, safety_weeks=1)
names = ["小売", "卸", "二次卸", "工場"]
for name, o in zip(names, orders):
print(f"{name}: 最大発注 {max(o):.1f} 分散の比 {np.var(o) / np.var(demand):.1f}")は、36 週間にわたる 4 段階の発注量を計算します。条件は以下の通りです。
- 期間:36 週
- 段階数:4 段階(小売、卸、二次卸、工場)
- 初期需要:4 個/週
- 変化後の需要:8 個/週
- 変化のタイミング:8 週目
- リードタイム:2 週
- 安全在庫期間:1 週
このシミュレーションでは、8 週目に最終需要が 4 個/週から 8 個/週へステップ状に変化します。各段階は、この変化を自分の受注を通じて遅れて認識します。コードは、この遅れと予測の連鎖によって、上流ほど発注量の振れが大きくなる現象を数値化します。計算例の数値は、乱数で生成した架空のサンプルデータに基づいています。(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))
上流ほど発注が暴れる
最終需要の主な変化は 8 週目に 4 個/週から 8 個/週へ増えたことですが、サプライチェーンの上流に進むほど発注量の振れは大きくなります。

このシミュレーションでは、小売段階の最大発注量は 14.0個 でした。一方、工場段階では 56.3個 まで上昇しています(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
段階ごとの詳細な数値は以下の表の通りです。
| 段階 | 最大発注量 | 標準偏差 | 分散の比(最終需要=1) |
|---|---|---|---|
| 小売 | 14.0個 | 2.6個 | 1.9倍 |
| 卸 | 21.4個 | 4.0個 | 4.6倍 |
| 二次卸 | 33.8個 | 6.9個 | 13.7倍 |
| 工場 | 56.3個 | 12.7個 | 46.0倍 |
(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))
分散の比を見ると、小売が 1.9倍 であるのに対し、工場は 46.0倍 に達しています。卸は 4.6倍、二次卸は 13.7倍 であり、上流ほど最終需要に対する変動の増幅が顕著であることが示されています(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
増幅の度合いを数字で見る
ここでは、最終需要の分散を基準に 1 としたときの、各段階の発注量の分散の比を確認します。

表を見ると、小売段階の分散の比は 1.9 倍です。卸段階では 4.6 倍、二次卸では 13.7 倍と、段階が上がるにつれて数値が大きくなっています。最も上流の工場段階では、分散の比が 46.0 倍に達しています(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。
この数値は、最終需要の振れに対して、工場の発注量の振れが約 46 倍に増幅されていることを示しています。小売段階の 1.9 倍と工場の 46.0 倍を比較すると、サプライチェーンの上流ほど、需要変動の影響が強く現れていると読めます。この差は、各段階が下流の発注のみを予測の根拠とする構造から生じています。
増幅を抑えるには
ブルウィップ効果の増幅を抑えるには、シミュレーションで増幅を生んだ要因を一つずつ見直す視点が役立ちます。まず、各段階が自分の受注しか見えない情報遅れを解消します。最終需要を全段階で共有すれば、予測の連鎖による増幅は小さくなると読めます。
次に、リードタイムの影響です。リードタイムが長いほど目標在庫が大きくなり、予測の変化が発注量の変化に倍加されます。したがって、リードタイムの短縮は有効な対策となります。
また、予測の過剰反応を抑えることも重要です。平滑化係数 α を大きくすると予測が受注に過剰反応し、増幅が強まります。小さくすれば増幅は弱まりますが、本当の変化への追随も遅れる点に注意が必要です。
さらに、発注のまとめ(ロット)や販促による駆け込みも増幅の原因になりますが、これらは本シミュレーションには含めていません。
まとめ
ブルウィップ効果は、情報の遅れと予測の連鎖で上流ほど発注が振れる現象です。Python による 4 段階のシミュレーションでは、工場段階の発注振れが最終需要の 46.0 倍に達しました(出典:本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード))。増幅を抑えるには、リードタイム短縮や平滑化係数の調整が有効です。
計算方法と注意
- 各段階は自分の受注しか見えず、最終需要を知らない(情報の遅れ)。最終需要を全段階で共有すれば、予測の連鎖による増幅は小さくなる
- リードタイムが長いほど目標在庫が大きくなり、予測の変化が発注量の変化に倍加される。リードタイム短縮は対策になる
- 平滑化係数 α を大きくすると予測が受注に過剰反応し、増幅が強まる。小さくすれば増幅は弱まるが、本当の変化への追随も遅れる
- 発注のまとめ(ロット)や販促による駆け込みも増幅の原因になるが、このシミュレーションには含めていない
- 計算例の数値は架空のシミュレーションによるもの
出典
- 本記事の Python コードによる計算(乱数で生成した架空のサンプルデータ、固定シード)
関連記事
本記事のコードと数値は、乱数で生成した架空のサンプルデータによる再現可能な計算例です。

