Mímisbrunnr知恵の泉

← シミュレーション 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:セルオートマトン | 関連:群集・流行のエージェントモデル

要点(BLUF)

1. モデルの設定

格子上に2種類のエージェント(例:●と○)と空き地を配置します。

重要なのは、許容度 τ\tau過半数を要求しない緩い値(例 τ=0.4\tau=0.4、つまり「近所の4割が同類なら満足、過半数が異類でも我慢」)でも、結果がどうなるか、です。

2. 実装

import numpy as np

def schelling(L, empty_frac, tol, steps, seed):
    rng = np.random.default_rng(seed)
    n = L*L
    n_empty = int(n*empty_frac)
    n_agent = n - n_empty
    # 0=タイプA, 1=タイプB, -1=空き
    cells = np.array([0]*(n_agent//2) + [1]*(n_agent - n_agent//2) + [-1]*n_empty)
    rng.shuffle(cells)
    grid = cells.reshape(L, L)

    def similar_frac(grid):                 # 同類隣人割合の平均
        fracs = []
        for i in range(L):
            for j in range(L):
                if grid[i,j] == -1: continue
                neigh = [grid[(i+di)%L, (j+dj)%L]
                         for di in (-1,0,1) for dj in (-1,0,1) if not (di==0 and dj==0)]
                same = sum(1 for x in neigh if x == grid[i,j])
                tot  = sum(1 for x in neigh if x != -1)
                if tot > 0: fracs.append(same/tot)
        return np.mean(fracs)

    start = similar_frac(grid)
    for s in range(steps):
        empties = list(zip(*np.where(grid == -1)))
        idxs = [(i,j) for i in range(L) for j in range(L) if grid[i,j] != -1]
        rng.shuffle(idxs)
        moved = 0
        for (i,j) in idxs:
            neigh = [grid[(i+di)%L, (j+dj)%L]
                     for di in (-1,0,1) for dj in (-1,0,1) if not (di==0 and dj==0)]
            same = sum(1 for x in neigh if x == grid[i,j])
            tot  = sum(1 for x in neigh if x != -1)
            if tot > 0 and same/tot < tol:          # 不満→空き地へ引っ越す
                k = rng.integers(len(empties)); (ei,ej) = empties[k]
                grid[ei,ej] = grid[i,j]; grid[i,j] = -1
                empties[k] = (i,j); moved += 1
        if moved == 0: break
    return start, similar_frac(grid)

start, end = schelling(L=40, empty_frac=0.1, tol=0.4, steps=50, seed=7)
print(f"許容度40%: 同類隣人割合  開始={start:.3f} → 終了={end:.3f}")

出力:

許容度40%: 同類隣人割合  開始=0.507 → 終了=0.840

出力の意味:初期はランダム配置なので同類隣人割合は約0.51(ほぼ五分五分)。ところが「近所の4割が同類なら満足」という緩い基準で引っ越しを繰り返すだけで、最終的に同類隣人割合が0.84まで上昇——近所のほとんどが同類、という強い分居が生まれました。誰も「分居したい」とは思っていない(過半数が異類でも我慢する設定)のに、です。

3. なぜ緩い好みが強い分居を生むのか

ポイントは連鎖反応です。あるエージェントが不満で引っ越すと、その人が抜けた近所では残った人の同類割合が変わり、新たな不満が生まれる。引っ越し先でも周囲のバランスを崩す。この小さな調整が雪だるま式に伝播し、系全体が「同類が固まった」安定配置へ流れ込みます。個人の許容度(4割でOK)と、実現するマクロ状態(8割同類)の間には大きなギャップがある——これが Schelling の洞察で、「マクロな分居は、必ずしも強い差別的選好の証拠ではない」という社会科学的含意を持ちます。

数式の直観的意味

Schelling モデルは「個人の効用関数の最適化が、社会全体では誰も望まない均衡に至る」例です。各エージェントは局所的な満足だけを追求(τ\tau 以上なら動かない)しますが、その局所最適化の集積が大域的な秩序(分居)を作る。これはセルオートマトンの創発と同じ構図——局所ルールの反復がマクロ構造を決める——を、効用と移動という社会的な装置で表したもの。乱数(引っ越し先の選択・更新順)が入る点が決定的なライフゲームと違い、結果はシード依存でばらつきますが、「緩い選好→強い分居」という定性的な創発は頑健に再現されます。許容度 τ\tau を上げていくと、ある点から分居が急に強まる閾値的な振る舞いも見られ、これは次の流行モデルの閾値現象と通じます。

⚠️ よくある誤解・落とし穴

対応シミュレーション参照

本文の Schelling 分居(default_rng(7)、許容度0.4で同類割合 0.51→0.84)。

関連ノート