Reputation: 5
I have a problem where I am supposed to model the Schelling Segregation problem using Python
. I have been stuck on this for quite a while now, but I think my issue is that my neighbours aren't being swapped correctly from an unhappy agent into an empty agent.
**Scope of problem: ** We have a matrix with 0s and 1s and 2s. Os represent empty houses, 1s represent one type of ethnicity, 2s represent another ethnicity. If one ethnicity isn't happy with their fraction of neighbours (defined by self.par) being similar to them, they then become unhappy agents. These unhappy agents need to swapped to empty houses. This needs to reiterated over multiple time steps and the metric (i.e. frac_mean as defined by code below) should decrease as people become "happied"
However, my issue is that the frac mean metric is not showing a consistent patter of decrease.
** Things I have tried: ** The main thing I tried was instead of making the swaps in the original self.array, I made a copy of it and made all swaps on that, then equated it to the original self array as seen by the second last line of the code.
Any help would be appreciated:
class Schelling():
kernel = [[1,1,1],[1,0,1],[1,1,1]]
#par = 0.3
def __init__(self, n, par=0.3):
self.par=par
probs = [0.1, 0.45, 0.45]
choices = [0, 1, 2]
self.array = np.random.choice(choices, (n, n), p=probs)
def count_neighbours(self):
a = self.array
empty = a == 0
red = a == 1
blue = a == 2
num_red = correlate2d(red, self.kernel, mode='same', boundary='wrap')
num_blue = correlate2d(blue, self.kernel, mode='same', boundary='wrap')
num_neighbours = num_red + num_blue
frac_red = num_red / num_neighbours
frac_blue = num_blue / num_neighbours
frac_red[num_neighbours == 0] = 0
frac_blue[num_neighbours == 0] = 0
# Nice way to do a vector if-else application
frac_same = np.where(red, frac_red, frac_blue)
# Because only if-else, empty will have frac_blue, so we need to correct this
frac_same[empty] = np.nan
return empty, frac_red, frac_blue, frac_same, a
def step(self):
empty, frac_red, frac_blue, frac_same, count_neighbours_list = self.count_neighbours()
metric=np.nanmean(frac_same)
unhappy_address = list(zip(*np.array(np.nonzero(frac_same < self.par))))
np.random.shuffle(unhappy_address)
empty_address = list(zip(*np.array(np.nonzero(empty))))
# Perform swaps until no more swaps are possible
unhappy_copy=unhappy_address.copy()
empty_copy=empty_address.copy()
ind=len(unhappy_copy)
#ind=min(len(unhappy_address), len(empty_address))
for i in range(ind):
#adding a check:
#add in a break: for the value of i if its greater than len-1 of empty_address, then break
if i == len(empty_address):
break
else:
unhappy_tup_req=unhappy_copy[i]
emp_tup_req=empty_copy[i]
#count_neighbours_list[emp_tup_req]=count_neighbours_list[unhappy_tup_req]
#count_neighbours_list[unhappy_tup_req]==0
count_neighbours_list[emp_tup_req], count_neighbours_list[unhappy_tup_req] = count_neighbours_list[unhappy_tup_req], count_neighbours_list[emp_tup_req]
self.array= count_neighbours_list
return unhappy_address, empty_address, count_neighbours_list, metric
Upvotes: 0
Views: 137
Reputation: 1
Here are some things you can try:
swap
function.update
function.Here is an example of how you can implement the above steps in Python:
def schelling_segregation(array, similarity_threshold):
"""
This function implements the Schelling segregation model.
Args:
array: A 2D array representing the city.
similarity_threshold: The threshold that is used to determine if an agent is happy.
Returns:
A 2D array representing the final state of the city.
"""
# Initialize the list of unhappy agents.
unhappy_agents = []
# Loop through the array and identify the unhappy agents.
for i in range(len(array)):
for j in range(len(array[0])):
if array[i][j] != 0:
fraction_of_neighbors = 0
for neighbor in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
if 0 <= neighbor[0] < len(array) and 0 <= neighbor[1] < len(array[0]):
if array[neighbor[0]][neighbor[1]] == array[i][j]:
fraction_of_neighbors += 1
if fraction_of_neighbors < similarity_threshold:
unhappy_agents.append((i, j))
# Loop through the list of unhappy agents and swap them with an empty house.
for i, j in unhappy_agents:
while True:
empty_house = None
for neighbor in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
if 0 <= neighbor[0] < len(array) and 0 <= neighbor[1] < len(array[0]):
if array[neighbor[0]][neighbor[1]] == 0:
empty_house = neighbor
break
if empty_house is not None:
array[i][j], array[empty_house[0]][empty_house[1]] = array[empty_house[0]][empty_house[1]], array[i][j]
break
return array
I hope this helps!
Upvotes: 0