2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ホテリングの法則シミュレーターを作ってみた

2
Last updated at Posted at 2026-05-06

はじめに

牛丼チェーンの「吉野家」と「すき家」などの同業他社が同じ交差点の角に並んで建っているのを見て、「わざわざ同じ場所に集まるんだろう?」 と疑問に思ったことはありませんか?

実は、経済学的な理由があります。ハロルド・ホテリングが提唱した 「競合する企業は互いに立地を近づけていく傾向がある」という原理 が、「ホテリングの法則」と呼ばれています。

今回は、この法則を検証するため1次元・2次元・3次元の空間でシミュレーションできるWebアプリを作りました。

ホテリングの法則とは

ホテリングの法則とは、どんなものなのか簡単に説明したいと思います。

A店舗とB店舗があり、周囲には住民が均一に分布しているとします。

ルール

各店舗は以下のルールに従って行動します。
① ユーザーは最も近い店舗へ行く(=その店舗の売り上げになる)
② 獲得ユーザー数が最も少ない店舗が、最もユーザーを獲得できる位置に移動する

処理イメージ

A店舗よりB店舗のほうが獲得ユーザーが少ない状態です。
1.png

B店舗が一番ユーザーを獲得できる場所はA店舗のすぐ右になります。
2.png

次にA店舗は、B店舗のすぐ右に移動します。
3.png

この繰り返しが起きると、最終的に2店舗とも中央に集まります。

4.png

これがナッシュ均衡(どちらも動いても得をしない状態)です。

社会全体の観点では、両端の住民が遠くまで歩かなければならないため非効率ですが、個々の事業者にとっては合理的な行動です。

アルゴリズム

シミュレーションの核となる「最適位置を探す」アルゴリズムを紹介します。

基本的な考え方

各住民は最も近い店舗を選びます。あるストアが「今の位置から動いたとき、何人の客を獲得できるか」をフィールド上のすべての候補地について計算し、最も多く獲得できる位置に移動します。

距離の定義

次元ごとに使う距離関数が異なります。

1次元

|a - b|

2次元

\sqrt{(a_x - b_x)^2 + (a_y - b_y)^2}

3次元

\sqrt{(a_x - b_x)^2 + (a_y - b_y)^2 + (a_z - b_z)^2}

※2次元・3次元の内部実装では比較に距離の二乗を使い、√(ルート) を省略して高速化しています。

処理の高速化

愚直に実装すると「全候補地 × 全住民 × 全店舗」の計算が必要になり非常に遅くなります。
そこで次のような2ステップで高速化しています。

ステップ1:各住民について、対象店舗以外の最近傍店舗を事前計算

const minOther = people.map((p) => {
  let minD = Infinity, minI = Infinity;
  for (let i = 0; i < stores.length; i++) {
    if (i === storeIdx) continue; // 対象店舗はスキップ
    const d = dist2(p, stores[i]);
    if (d < minD || (d === minD && i < minI)) { minD = d; minI = i; }
  }
  return { d: minD, i: minI }; // 他店舗への最短距離を記録
});

ステップ2:全候補地でその事前計算結果と比較するだけで判定

for (let x = 0; x < N; x++) {
  for (let y = 0; y < N; y++) {
    let c = 0;
    for (let pi = 0; pi < people.length; pi++) {
      const dx = people[pi].x - x;
      const dy = people[pi].y - y;
      const d = dx * dx + dy * dy; // 二乗距離(sqrt不要で高速)
      // 候補地のほうが近ければ獲得
      if (d < minOther[pi].d ||
         (d === minOther[pi].d && storeIdx < minOther[pi].i)) c++;
    }
    if (c > bestCount) { bestCount = c; best = { x, y }; }
  }
}

ステップ1を先に行っておくことで、ステップ2では「候補地までの距離と事前計算した値を比べるだけ」で判定できます。事前計算を行わない場合は、全候補地で全住民×全店舗の距離を毎回計算し直すため、店舗数が増えるほど処理が遅くなります。

完成したもの

1次元シミュレーション

横方向だけのシミュレーションです。
実行ボタンを押すと、最も市場シェアが低い店舗が自動的に最適位置へ移動し続けます。繰り返すと、店舗が隣り合わせになり、だんだんと店舗が中央に集まる様子が確認できます。

Animation1.gif

2次元シミュレーション

XY座標上でシミュレーションします。
1次元と同様に自動実行を繰り返すと、複数の店舗がフィールドの中心付近に密集していきます。

Animation1.gif

3次元シミュレーション

Three.jsを使って3次元空間上でシミュレーションします。
3次元においても同様に、店舗は空間の中心へ引き寄せられるように収束していきます。

Animation1.gif

宇宙空間でもホテリングの法則は通用しそうです。

競合店舗を増やしてみる

3店舗以上の競合がある場合、ホテリングの法則は適用されないと言われています。

実際に描画してみると、ボロノイ図のように各店舗の勢力圏が色分けされます。ステップ実行しても、すべての店舗が同じ場所に集中することはなく、最下位争いをする小競り合いは発生するものの、ホテリングの法則のような収束傾向は見られませんでした。

Animation1.gif

おわりに

今回はホテリングの法則を1次元・2次元・3次元でシミュレーションしました。

理論として語られていることを実際に視覚化したり、競合店舗を増やして試したりできるのが、シミュレーターの面白いところですね。また、同一チェーンの店舗を増やしてみたり、実際の地図上でシミュレートしたりしても面白そうです。

興味のある方は、Webページを用意していますのでぜひ触ってみてください。

Webシミュレーター

GitHub リポジトリ

ここまで読んでいただきありがとうございました。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?