终于回归CSDN,打算这次坚持到底!立个FLAG!
曾经在美赛中生搬硬套了这个模型,现在终于得空,打算研究一下。
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.width = width
self.height = height
self.races = races
self.empty_ratio = empty_ratio
self.similarity_threshold = similarity_threshold
self.n_iterations = n_iterations
self.empry_house = []
self.agents={}
def populate(self):
self.all_house = 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(self.agents.items()+dict(zip(house_by_race[i],[i+1]*len(houses_by_race[i]))).items()
is_unsatisfied 方法把房屋的 (x, y) 坐标作为传入参数,查看同种群邻居的比例,如果比理想阈值(happiness threshold)高则返回 True,否则返回 False。
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)
update 方法将查看网格上的居民是否尚未满意,如果尚未满意,将随机把此人分配到空房子中。并模拟 n_iterations 次
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:
if self.is_unhappy(agent[0], agent[1]):
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
move_to_empty 方法把房子坐标(x, y)作为传入参数,并将 (x, y) 房间内的居民迁入空房子。这个方法被 update 方法调用,会把尚不满意的人迁入空房子。
def move_to_empty(self, x, y):
race = self.agents[(x,y)]
empty_house = random.choice(self.empty_houses)
self.updated_agents[empty_house] = race
del self.updated_agents[(x, y)]
self.empty_houses.remove(empty_house)
self.empty_houses.append((x, y))
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)
宽 = 50,而高 = 50(包含 2500 间房子)
30% 的空房子
相似性阈值 = 30%(针对仿真 1),相似性阈值 = 50%(针对仿真 2),相似性阈值 = 80%(针对仿真 3)
最大迭代数 = 500
种族数量 = 2
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_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')
def calculate_similarity(self):
similarity = []
for agent in self.agents:
count_similar = 0
count_different = 0
x = agent[0]
y = agent[1]
race = self.agents[(x,y)]
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
try:
similarity.append(float(count_similar)/(count_similar+count_different))
except:
similarity.append(1)
return sum(similarity)/len(similarity)
similarity_threshold_ratio = {}
for i in [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7]:
schelling = Schelling(50, 50, 0.3, i, 500, 2)
schelling.populate()
schelling.update()
similarity_threshold_ratio[i] = schelling.calculate_similarity()
fig, ax = plt.subplots()
plt.plot(similarity_threshold_ratio.keys(), similarity_threshold_ratio.values(), 'ro')
ax.set_title('Similarity Threshold vs. Mean Similarity Ratio', fontsize=15, fontweight='bold')
ax.set_xlim([0, 1])
ax.set_ylim([0, 1.1])
ax.set_xlabel("Similarity Threshold")
ax.set_ylabel("Mean Similarity Ratio")
plt.savefig('schelling_segregation_measure.png')
宽 = 50,而高 = 50(包含 2500 间房子)
30% 的空房子
相似性阈值 = 30%(针对仿真 1),相似性阈值 = 50%(针对仿真 2),相似性阈值 = 80%(针对仿真 3)
最大迭代数 = 500
种族数量 = 2