ランチェスターの法則でマーケティング分析!一般化モデルとPythonでのシミュレーションを試してみました...
はじめに:戦場からビジネスへ、数学で切り込む!
ランチェスターの法則、皆さんはご存知でしょうか? 1914年にイギリスの数学者フレデリック・ランチェスターが航空戦を分析するために作った数理モデルです。戦場で兵士が減っていく様子を微分方程式で表現し、どちらが勝つかを計算します。シンプルだけど、めっちゃ奥深いんですよ! これが、ビジネスの世界、例えば市場シェアや売上の争いにもバッチリ応用できるんです。
今回は、日本のSIerを題材に、ランチェスターの法則をちょっとアレンジして遊んでみました。対象は某SIer4社です。第一法則と第二法則をパラメータで一般化し、2者対立をn者対立に拡張。さらに、2013~2024年の有価証券報告書の売上データを使ってPythonでシミュレーションしてみました。紅茶片手に、じっくり楽しんでください!
ランチェスターの法則の基礎:戦場を数式で読み解く
ランチェスターの法則は、戦闘の損耗を微分方程式でモデル化するもの。ビジネスでは、売上高や顧客数を「兵力」、技術力やブランド力を「戦闘効率」とみなします。2つの法則を、式変形とともに詳しく見ていきましょう。ちなみにここで示す各種変数は以下になります。
-
: 自社のリソース(例: 売上高、顧客数)X -
: 競合のリソースY -
: 自社の戦闘効率(技術力、ブランド力)a -
: 競合の戦闘効率b
第一法則:一騎打ちのシンプルな戦い
第一法則は、古代の剣や槍の戦いみたいな一対一のシチュエーションを想定します。相手の人数は関係なく、武器の性能(戦闘効率)だけで勝負が決まるんです。ビジネスだと、ニッチ市場で技術力や品質がモノを言うケースですね。例えば、スタートアップが独自のアルゴリズムで大手に挑むような場面です。
第二法則:数で押す近代戦
第二法則は、銃や火砲を使った集団戦闘を想定。損耗率が相手の兵力数に比例するので、リソースが多い方が圧倒的に有利です。ビジネスでは、市場シェアや広告予算の規模がモノを言う市場、例えばEコマースやクラウドサービスに当てはまります。
ランチェスターの第一法則と第二法則を一般化:中間を埋める
現実のビジネスを第一法則(効率だけで勝負)や第二法則(リソース量が大事)に当てはめるのは無理があります。第一法則と第二法則の間には、中間的なケースがたくさんありますよね。そこで、パラメータ
-
: 第一法則c = 0 ,(Y^0 = 1) (\frac{dX}{dt} = -b, \frac{dY}{dt} = -a) -
: 第二法則c = 1 ,( Y^1 = Y) (\frac{dX}{dt} = -b Y, \frac{dY}{dt} = -a X) -
: 中間法則0 < c < 1
n項対立への拡張:複数社間のバチバチな戦い
現実のビジネスは2者対立じゃなくて、複数企業がガチンコで競うことが多い。そこで、2者対立をn者対立に拡張してみました。
-
: 企業iのリソース(例: 売上高)X_i -
: 企業jの戦闘効率b_j -
: リソース依存度c
Pythonでシミュレーション:4社の売上データを試す
某SIer企業の有価証券報告書を参照し売上データを抽出して4社がどのような戦い方をしているのかPythonでささっと分析してみました。ちなみに値が大きいのでLog10でスケールを下げています。
import numpy as np
from scipy.integrate import odeint
from scipy.optimize import minimize
import matplotlib.pyplot as plt
# データの入力(年度降順なので昇順にソート)
years = np.array([2024, 2023, 2022, 2021, 2020, 2019, 2018, 2017, 2016, 2015, 2014, 2013])[::-1] # 2013 to 2024
data = np.array([
[9783370, 3550116, 3477262, 13374559],
[9728716, 3476985, 3313018, 13136194],
[10881150, 3713767, 3014095, 12156447],
[10264602, 3586839, 2994023, 11943966],
[8729196, 3589702, 3095234, 11899415],
[8767263, 3857797, 2913446, 11879842],
[9480619, 3952437, 2844447, 11782148],
[9368614, 4098379, 2665035, 11391016],
[9162264, 4132972, 2824833, 11540997],
[10034305, 4739294, 2935517, 11095317],
[9774930, 4753210, 3043114, 10925174],
[9666446, 4762445, 3071609, 10700740]
])[::-1, :] # 行を逆順にして2013から2024に
# 底10の対数スケールダウン
data_log = np.log10(data)
# 時間軸(2013をt=0, 2024をt=11)
t = np.arange(0, 12, 1) # 0 to 11 years
n = 4 # 企業数 (H, F, N, T)
# ランチェスターの一般化モデル(timeはodeintのために必要だが未使用)
def lanchester_model(X, time, b, c, n):
X = np.maximum(X, 0) # 負の値防止
dXdt = np.zeros(n)
for i in range(n):
sum_term = 0
for j in range(n):
if j != i:
sum_term += b[j] * (X[j] ** c)
dXdt[i] = -sum_term
return dXdt
# 目的関数(モデル予測とデータの誤差二乗和)
def objective(params, data, t, n):
b = params[:n]
c = params[n]
X0 = data[0, :] # 初期値 (2013年)
sol = odeint(lanchester_model, X0, t, args=(b, c, n))
error = np.sum((sol - data) ** 2)
return error
# 初期推定値(対数スケール後、bを適切な範囲に設定)
initial_guess = np.array([1.0, 1.0, 1.0, 1.0, 0.5]) # b1(H), b2(F), b3(N), b4(T), c
bounds = [(0, 10)] * n + [(0, 1)] # bの範囲を対数スケールに合わせて調整、cは0-1
# 最適化実行
result = minimize(objective, initial_guess, args=(data_log, t, n), bounds=bounds, method='L-BFGS-B')
estimated_b = result.x[:n]
estimated_c = result.x[n]
# 結果出力
print("Estimated b (H, F, N, T):", estimated_b)
print("Estimated c:", estimated_c)
# フィット結果のプロット(元のスケールに戻す)
plt.figure(figsize=(10, 6))
companies = ['H', 'F', 'N', 'T']
for i in range(n):
plt.plot(years, data[:, i], 'o', label=f'{companies[i]} Data')
plt.plot(years, 10 ** odeint(lanchester_model, data_log[0, :], t, args=(estimated_b, estimated_c, n))[:, i], '-', label=f'{companies[i]} Fit')
plt.xlabel('Year')
plt.ylabel('Revenue (million yen)')
plt.title(f'Lanchester Model Fit (c={estimated_c:.3f})')
plt.legend()
plt.grid(True)
plt.show()
# 結果保存
np.savetxt('estimated_params_log.txt', np.append(estimated_b, estimated_c), header='b_H b_F b_N b_T c')
np.savetxt('data_log.txt', data_log, header='H F N T')
結果:
以下の値がが出力されました。
- Estimated b: [1.01760567 (N社), 1.01721865 (F社), 1.01721865 (N社), 0.99804381 (T社)]
- Estimated c: 0.5009393906445575
シミュレーション結果と現実の合致度:
b_j に関する考察
各社の
c に関する考察
各社の気づいた点:失敗と改善のメモ
シミュレーションやってみて、うまくいったところもあれば、盛大にコケたところも。失敗と改善点を正直にまとめます。
- ランチェスターの法則は「損耗」(リソース減)を前提にしてるけど、全社売上増。市場成長を無視したのが失敗。改善点:成長項をモデルに追加して、市場拡大を考慮。
- 初期推定値
や範囲( b_j = 1.0, c = 0.5) に依存しすぎ。最適化が局所解にハマった可能性。改善点:グリッドサーチやベイズ推定で、推定の安定性を上げる。( b_j \in [0, 10]) - DX・AI需要や景気変動が売上に影響してるのに、モデルは単純な競争のみ。失敗:これを無視したこと。改善点:外部変数をモデルに組み込む。
Discussion