从经济学到代码:用ABM仿真理解谢林隔离现象(Python实战版)
·
从经济学到代码:用ABM仿真理解谢林隔离现象(Python实战版)
当托马斯·谢林在1971年用硬币和方格纸演示种族隔离现象时,这位经济学家可能没想到,半个世纪后人们会用Python代码重现他的思想实验。这个看似简单的模型揭示了一个深刻悖论:即使每个个体只表现出轻微的偏好,整个群体也会自发形成高度隔离的模式。今天,我们将用不到100行Python代码,让这个经典的社会学模型在计算机中"活"过来。
1. 谢林模型的核心洞察
1.1 微观行为与宏观现象的鸿沟
谢林模型最颠覆性的发现是:群体层面的隔离程度与个体偏好强度并非线性相关。通过调整几个关键参数,我们会看到三种典型状态:
| 阈值区间 | 宏观表现 | 稳定状态 | 相似度特征 |
|---|---|---|---|
| 20%-40% | 轻度隔离 | 静态稳定 | 略高于随机分布 |
| 40%-65% | 显著隔离 | 静态稳定 | 形成明显聚居区 |
| 65%以上 | 动态混沌 | 持续流动 | 实际相似度反而下降 |
注意:当阈值超过65%时,系统会进入"过度挑剔"状态,居民不断搬家导致无法形成稳定社区。
1.2 模型的社会学启示
- 非意图后果:隔离可能是无意识个体行为的自然结果
- 临界阈值:存在使系统性质突变的敏感参数区间
- 政策启示:仅观察宏观隔离无法推断微观歧视程度
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# 初始化参数
GRID_SIZE = 50
THRESHOLD = 0.4 # 尝试调整这个关键参数观察不同现象
2. Python实现完整流程
2.1 智能体世界的构建
我们首先创建一个二维网格世界,包含三类单元格:
- 红色智能体(占比40%)
- 蓝色智能体(占比40%)
- 空白格(占比20%)
def initialize_grid():
"""创建初始随机分布"""
status = ["red", "blue", "empty"]
proportions = [0.4, 0.4, 0.2]
grid = np.random.choice(status, size=(GRID_SIZE, GRID_SIZE), p=proportions)
return grid
2.2 满意度计算引擎
每个智能体评估周围8个邻居的构成情况:
def calculate_happiness(grid, i, j):
"""计算指定位置的满意度"""
if grid[i,j] == "empty":
return None
same = 0
different = 0
for x in range(max(0,i-1), min(GRID_SIZE,i+2)):
for y in range(max(0,j-1), min(GRID_SIZE,j+2)):
if (x,y) == (i,j) or grid[x,y] == "empty":
continue
if grid[x,y] == grid[i,j]:
same += 1
else:
different += 1
total = same + different
return same / total if total > 0 else 0
2.3 迁移动态系统
不满意智能体的迁移遵循以下规则:
- 随机选择一个空白格
- 交换当前位置与空白格的状态
- 更新满意度矩阵
def update_grid(grid):
"""执行一轮迁移过程"""
unhappy_positions = []
empty_positions = list(zip(*np.where(grid == "empty")))
# 找出所有不满意智能体
for i in range(GRID_SIZE):
for j in range(GRID_SIZE):
happiness = calculate_happiness(grid, i, j)
if happiness and happiness < THRESHOLD:
unhappy_positions.append((i,j))
# 随机迁移不满意智能体
np.random.shuffle(unhappy_positions)
for i,j in unhappy_positions:
if empty_positions:
target = empty_positions.pop()
grid[i,j], grid[target] = "empty", grid[i,j]
return len(unhappy_positions)
3. 可视化与动态分析
3.1 实时动画呈现
使用Matplotlib的动画功能展示演化过程:
def animate_schelling():
fig, ax = plt.subplots(figsize=(10,8))
grid = initialize_grid()
img = ax.imshow(np.where(grid=="red",1,np.where(grid=="blue",2,0)),
cmap="cool", vmin=0, vmax=2)
def update(frame):
nonlocal grid
update_grid(grid)
img.set_array(np.where(grid=="red",1,np.where(grid=="blue",2,0)))
return img,
ani = FuncAnimation(fig, update, frames=100, interval=200, blit=True)
plt.title(f"谢林模型仿真 (阈值={THRESHOLD})")
plt.show()
3.2 关键指标追踪
建立监控系统记录:
- 平均相似度
- 不满意比例
- 迁移次数
def track_metrics(grid):
metrics = {
'similarity': [],
'unhappy_ratio': [],
'moves': 0
}
for _ in range(100): # 模拟100轮
moves = update_grid(grid)
metrics['moves'] += moves
# 计算全局指标
similarities = []
unhappy = 0
total = 0
for i in range(GRID_SIZE):
for j in range(GRID_SIZE):
if grid[i,j] != "empty":
happiness = calculate_happiness(grid, i, j)
similarities.append(happiness)
if happiness < THRESHOLD:
unhappy += 1
total += 1
metrics['similarity'].append(np.mean(similarities))
metrics['unhappy_ratio'].append(unhappy/total if total >0 else 0)
return metrics
4. 进阶实验设计
4.1 多参数对比实验
通过系统性地调整参数,我们可以绘制出系统的相变图:
def parameter_experiment():
thresholds = np.linspace(0.2, 0.8, 7)
results = []
for th in thresholds:
global THRESHOLD
THRESHOLD = th
grid = initialize_grid()
metrics = track_metrics(grid)
results.append({
'threshold': th,
'final_similarity': metrics['similarity'][-1],
'total_moves': metrics['moves']
})
# 绘制结果曲线
plt.figure(figsize=(12,5))
plt.subplot(121)
plt.plot([r['threshold'] for r in results],
[r['final_similarity'] for r in results], 'o-')
plt.xlabel('满意度阈值')
plt.ylabel('最终平均相似度')
plt.subplot(122)
plt.plot([r['threshold'] for r in results],
[r['total_moves'] for r in results], 's-')
plt.xlabel('满意度阈值')
plt.ylabel('总迁移次数')
plt.tight_layout()
4.2 模型变体探索
- 异质智能体:不同群体设置不同阈值
- 移动成本:引入迁移阻力系数
- 空间约束:限制迁移最大距离
class AdvancedAgent:
def __init__(self, group, mobility=1.0):
self.group = group
self.threshold = np.random.normal(0.5, 0.1) # 个体差异
self.mobility = mobility # 迁移倾向
def decide_move(self, neighborhood):
similar = sum(1 for n in neighborhood if n == self.group)
ratio = similar / len(neighborhood)
return ratio < self.threshold and np.random.rand() < self.mobility
5. 从仿真到现实应用
当我们将这个简单模型与现实数据对比时,会发现惊人的一致性。以芝加哥市的人口分布为例,尽管没有明确的隔离政策,城市依然形成了明显的种族聚居区。模型的预测能力使其在以下领域展现出价值:
- 城市规划:预测公共服务需求分布
- 市场分析:模拟消费者聚集效应
- 政策评估:测试不同干预措施效果
在完成基础实现后,建议尝试将这些代码封装成类结构,添加更多现实因素。例如,引入经济梯度、交通网络等要素,会使模型更加贴近真实城市系统。
更多推荐


所有评论(0)