import matplotlib.pyplot as plt
import itertools
import random
import copy
class Schelling:
def __init__(self, width, height, empty_ratio, similarity_threshold, n_iterations, races=2):
self.old_agents = None
self.remaining_houses = None
self.n_empty = None
self.all_houses = None
self.width = width
self.height = height
self.races = races
self.empty_ratio = empty_ratio
self.similarity_threshold = similarity_threshold
self.n_iterations = n_iterations
self.empty_houses = []
self.agents = {}
def populate(self):
self.all_houses = list(itertools.product(range(self.width), range(self.height)))
random.shuffle(self.all_houses)
self.n_empty = int(self.empty_ratio * len(self.all_houses))
self.empty_houses = self.all_houses[:self.n_empty]
self.remaining_houses = self.all_houses[self.n_empty:]
houses_by_race = [self.remaining_houses[i::self.races] for i in range(self.races)]
for i in range(self.races):
self.agents = dict(
list(self.agents.items()) + list(dict(zip(houses_by_race[i], [i + 1] * len(houses_by_race[i]))).items()))
def is_unsatisfied(self, x, y):
race = self.agents[(x, y)]
count_similar = 0
count_different = 0
if x > 0 and y > 0 and (x - 1, y - 1) not in self.empty_houses:
if self.agents[(x - 1, y - 1)] == race:
count_similar += 1
else:
count_different += 1
if y > 0 and (x, y - 1) not in self.empty_houses:
if self.agents[(x, y - 1)] == race:
count_similar += 1
else:
count_different += 1
if x < (self.width - 1) and y > 0 and (x + 1, y - 1) not in self.empty_houses:
if self.agents[(x + 1, y - 1)] == race:
count_similar += 1
else:
count_different += 1
if x > 0 and (x - 1, y) not in self.empty_houses:
if self.agents[(x - 1, y)] == race:
count_similar += 1
else:
count_different += 1
if x < (self.width - 1) and (x + 1, y) not in self.empty_houses:
if self.agents[(x + 1, y)] == race:
count_similar += 1
else:
count_different += 1
if x > 0 and y < (self.height - 1) and (x - 1, y + 1) not in self.empty_houses:
if self.agents[(x - 1, y + 1)] == race:
count_similar += 1
else:
count_different += 1
if x > 0 and y < (self.height - 1) and (x, y + 1) not in self.empty_houses:
if self.agents[(x, y + 1)] == race:
count_similar += 1
else:
count_different += 1
if x < (self.width - 1) and y < (self.height - 1) and (x + 1, y + 1) not in self.empty_houses:
if self.agents[(x + 1, y + 1)] == race:
count_similar += 1
else:
count_different += 1
if (count_similar + count_different) == 0:
return False
else:
return float(count_similar) / (count_different + count_similar) < self.happy_threshold
def update(self):
for i in range(self.n_iterations):
self.old_agents = copy.deepcopy(self.agents)
n_changes = 0
for agent in self.old_agents:
agent_race = self.agents[agent]
empty_house = random.choice(self.empty_houses)
self.agents[empty_house] = agent_race
del self.agents[agent]
self.empty_houses.remove(empty_house)
self.empty_houses.append(agent)
n_changes += 1
print(n_changes)
if n_changes == 0:
break
def plot(self, title, file_name):
fig, ax = plt.subplots()
# 如果要进行超过 7 种颜色的仿真,你应该相应地进行设置
agent_colors = {1: 'b', 2: 'r', 3: 'g', 4: 'c', 5: 'm', 6: 'y', 7: 'k'}
for agent in self.agents:
ax.scatter(agent[0] + 0.5, agent[1] + 0.5, color=agent_colors[self.agents[agent]])
ax.set_title(title, fontsize=10, fontweight='bold')
ax.set_xlim([0, self.width])
ax.set_ylim([0, self.height])
ax.set_xticks([])
ax.set_yticks([])
plt.savefig(file_name)
if __name__ == '__main__':
schelling_1 = Schelling(50, 50, 0.3, 0.3, 500, 2)
schelling_1.populate()
schelling_2 = Schelling(50, 50, 0.3, 0.5, 500, 2)
schelling_2.populate()
schelling_3 = Schelling(50, 50, 0.3, 0.8, 500, 2)
schelling_3.populate()
schelling_1.plot('Schelling Model with 2 colors: Initial State', 'schelling_2_initial.png')
schelling_1.update()
schelling_2.update()
schelling_3.update()
schelling_1.plot('Schelling Model with 2 colors: Final State with Similarity Threshold 30%',
'schelling_2_30_final.png')
schelling_2.plot('Schelling Model with 2 colors: Final State with Similarity Threshold 50%',
'schelling_2_50_final.png')
schelling_3.plot('Schelling Model with 2 colors: Final State with Similarity Threshold 80%',
'schelling_2_80_final.png')
运行结果