Модель сегрегации Шеллинга
Каждый агент согласен жить в смешанном окружении и хочет лишь, чтобы хотя бы 40% соседей были «своего» типа. Звучит как рецепт перемешанного общества. Модель Шеллинга показывает обратное: получается почти полное разделение.
Модель сегрегации Шеллинга — это клеточный автомат с агентами двух абстрактных типов на сетке, где каждый агент «доволен», если доля соседей своего типа не ниже заданного порога, а недовольные переезжают на случайную пустую клетку; модель демонстрирует, что даже умеренное локальное предпочтение приводит к сильной глобальной сегрегации.
Важно сразу оговорить: это абстрактная математическая модель «агентов двух типов», а не утверждение о людях, группах или обществе. Её ценность — методологическая: она показывает, что глобальный результат системы может радикально расходиться с намерениями отдельных её элементов. За работы в этом духе Томас Шеллинг получил Нобелевскую премию по экономике 2005 года. Мы изучаем её строго как пример эмерджентности.
Правила модели
На сетке живут агенты двух типов (обозначим их A и B) и есть пустые клетки. Окрестность — Мура (8 соседей). Для каждого агента:
- Смотрим на занятых соседей и считаем долю «своих» — того же типа.
- Агент доволен, если эта доля не ниже порога толерантности (в нашем примере
thr = 0.4, то есть достаточно 40% своих). - Недовольный агент переезжает на случайную свободную клетку. Довольные остаются на месте.
Парадокс в том, что порог 0.4 описывает очень терпимого агента: он не против оказаться в меньшинстве (40% — это меньше половины). И всё же на уровне всей сетки возникает чёткое разделение. Посмотрим на коде.
import random
random.seed(2)
R, C = 8, 8
cells = [(r, c) for r in range(R) for c in range(C)]
def make_grid():
g = [[0] * C for _ in range(R)]
spots = cells[:]
random.shuffle(spots)
n_each = 24
for i in range(n_each):
r, c = spots[i]
g[r][c] = 1
for i in range(n_each, 2 * n_each):
r, c = spots[i]
g[r][c] = 2
return g
g = make_grid()
def neighbors(g, r, c):
same = diff = 0
for dr in (-1, 0, 1):
for dc in (-1, 0, 1):
if dr == 0 and dc == 0:
continue
rr, cc = r + dr, c + dc
if 0 <= rr < R and 0 <= cc < C and g[rr][cc] != 0:
if g[rr][cc] == g[r][c]:
same += 1
else:
diff += 1
return same, diff
def happy(g, r, c, thr=0.4):
if g[r][c] == 0:
return True
same, diff = neighbors(g, r, c)
tot = same + diff
if tot == 0:
return True
return same / tot >= thr
def frac_unhappy(g):
tot = unh = 0
for r in range(R):
for c in range(C):
if g[r][c] != 0:
tot += 1
if not happy(g, r, c):
unh += 1
return unh / tot
def show(g):
sym = {0: '.', 1: 'A', 2: 'B'}
for row in g:
print(''.join(sym[x] for x in row))
print()
print("Старт, доля недовольных:", round(frac_unhappy(g), 3))
show(g)
for it in range(30):
empties = [(r, c) for r in range(R) for c in range(C) if g[r][c] == 0]
moved = False
for r in range(R):
for c in range(C):
if g[r][c] != 0 and not happy(g, r, c) and empties:
er, ec = random.choice(empties)
g[er][ec] = g[r][c]
g[r][c] = 0
empties.remove((er, ec))
empties.append((r, c))
moved = True
if not moved:
break
print(f"После {it + 1} итераций, доля недовольных:", round(frac_unhappy(g), 3))
show(g)
Вывод:
Старт, доля недовольных: 0.25 AB.AA.A. AA.AB.AA .BA.BAA. ABBBBBAA BABABB.A BB.BAAB. BAB.B..A .BBABB.A После 4 итераций, доля недовольных: 0.0 AAAAA.AA AA.AA.AA AAA.BAAA A.BBBBAA B.B.BBAA BB.B.BB. B.BBBB.. .BB.BBB.
Сравните две сетки. В начале A и B перемешаны почти случайно, недовольных четверть. После всего 4 итераций недовольных не осталось вовсе, но посмотрите, какой ценой: A собрались в верхней части поля, B — в нижней. Возникли крупные одноцветные области. Никто не стремился к сегрегации — каждый агент был согласен на 40% «чужих» соседей. Но сумма локальных переездов выстроила глобальное разделение.
Как работает под капотом
Функция neighbors обходит окрестность Мура и считает два числа: same (сколько соседей того же типа) и diff (другого). Пустые клетки в счёт не идут — условие g[rr][cc] != 0. Функция happy переводит это в решение: если занятых соседей нет (tot == 0), агент доволен по умолчанию; иначе сравнивает долю same / tot >= thr с порогом.
Главный цикл на каждой итерации заново собирает список пустых клеток empties, проходит по всем агентам и недовольных переселяет: выбирает случайную пустую клетку random.choice(empties), ставит туда агента, освобождает старую клетку и обновляет список пустот. Флаг moved отслеживает, был ли хоть один переезд; если за итерацию никто не двинулся — система достигла равновесия, и break прерывает цикл. В нашем прогоне равновесие (ноль недовольных) наступило за 4 шага.
Заметьте: в отличие от Игры «Жизнь», здесь обновление асинхронное — агенты переезжают по очереди, и переезд одного сразу влияет на расчёт для следующих в той же итерации. Это нормально для модели Шеллинга: она про последовательные индивидуальные решения, а не про одновременный пересчёт всего поля.
Частые ошибки
- Учитывать пустые клетки как соседей. Если в долю «своих» включать пустоты, порог станет считаться неверно. Доля берётся только от занятых соседей.
- Деление на ноль. У агента-отшельника без занятых соседей
tot == 0. Без отдельной проверкиsame / totупадёт с ошибкой. Такого агента логично считать довольным. - Забыть обновить список пустот. После переезда старая клетка становится пустой, а новая — занятой. Если не поддерживать
emptiesв актуальном состоянии, агенты начнут «переезжать» на занятые места. - Толковать модель буквально. Это абстракция про эмерджентность, а не описание реальных сообществ. Главный урок — методологический: глобальный исход может противоречить локальным намерениям.
Итоги
- Модель Шеллинга — автомат с агентами двух абстрактных типов и пустыми клетками на сетке.
- Агент доволен, если доля соседей своего типа не ниже порога толерантности; недовольные переезжают на случайное свободное место.
- Даже умеренный порог (например, 40% своих) приводит к сильной глобальной сегрегации — крупным одноцветным областям.
- Это эмерджентность: глобальный результат сильнее и неожиданнее индивидуальных намерений, в которых не было цели разделяться.
- Модель Шеллинга — абстрактный мысленный эксперимент (Нобелевская премия 2005 года), а не утверждение о людях.