8.2 Mit Schelling experimentieren
Contents
8.2 Mit Schelling experimentieren#
Nun ist es deine Aufgabe ein kleines Simulationsexperiment auf Basis des Schelling-Modells durchzuführen. In den Übungsaufgaben des letzten Kapitels solltest du dir ein mögliches Simulationsexperiment überlegen. Greife diese Überlegungen nun auf und setze sie um. Verwende als Ausgangspunkt entweder den (von dir modifizierten) Code aus dem letzten Kapitel oder den untigen Code.
Damit du ein Simulationsexperiment umsetzen kannst, musst du den Code so verändern, dass dieser
eine interessierende abhängige Variable misst
eine interessierende unabhängige Variable als Parameterwert in die Funktion
run_model()
eingegeben werden kannrelevante Modellinformationen durch die Funktion
run_model()
in einem Dictionary ausgegeben werdenin einem oder mehreren For-Loops die Funktion
run_model()
mit unterschiedlichen Werten für die unabhängige Variable deiner Wahl läuft und alle Dictionaries mit den Modellinformationen gespeichert werdendie Modellinformationen/Daten zu einem Pandas-Dataframe zusammengeführt werden
einfache graphische Auswertungen vollzogen werden.
Falls du dir in den letzten Übungsaufgaben kein Simulationsexperiment überlegt haben solltest, überprüfe den Zusammenhang zwischen indivdueller Segregations-Präferenz (threshold
) und der tatsächlich auf der Makroebene entstehenden Segregation. Als Maß für Segregation auf der Makroebene kannst du den durchschnittlichen Anteil von Mitgliedern der eigenen Gruppe innerhalb der Nachbarschaft verwenden. Dieser liegt für jede Zelle auf dem Zellen-Attribut "share_of_same_group"
vor. Aber Vorsicht: Zum einen musst du diesen Wert einmal für alle Zellen aktualisieren, bevor du den Durchschnitt berechnen kannst. Zum anderen musst du darauf achten, dass du nur gültige Werte bei der Mittelwertsberechnung beachtest, denn Agenten ohne direkte Nachbarn bekommen einen “ungültigen” Wert von 999
eingetragen.
Code zum Schelling-Modell (ohne grafische Darstellung)#
import random
def create_grid(n_rows, n_cols, n_group1, n_group2):
"""
Erstellt eine Matrix als geschachtelte Liste der Größe n_rows*n_cols.
Auf jede Zelle der Matrix wird ein Dictionary mit relevanten Zellen-Informationen gesetzt.
In die Zellen ziehen die Mitglieder der Gruppe 1 und Gruppe 2 entsprechend der durch n_group1 und n_group2
angegebenen Häufigkeiten ein.
"""
# Grid als Liste von Listen erstellen und auf jede Position eine unbewohnte Zelle setzen
grid = []
for i in range(n_rows):
row = []
for j in range(n_cols):
cell = {
"row": i,
"col": j,
"resident": 0,
"share_of_same_group": None,
"neighbor_cells": [],
}
row.append(cell)
grid.append(row)
# Alle Zellen auch in einer normalen, flachen Liste speichern,
# damit man einfacher per For-Loop alle Zellen durchgehen kann
cell_population = []
for row in grid:
for cell in row:
cell_population.append(cell)
# für jede Zelle die benachbarten Zellen finden
for cell in cell_population:
find_neighbor_cells(cell, grid)
# Agenten der Gruppe 1 auf Grid setzen
for i in range(n_group1):
empty_cells, occupied_cells = get_empty_and_occupied_cells(cell_population)
random_empty_cell = random.choice(empty_cells)
random_empty_cell["resident"] = 1
# Agenten der Gruppe 2 auf Grid setzen
for i in range(n_group2):
empty_cells, occupied_cells = get_empty_and_occupied_cells(cell_population)
random_empty_cell = random.choice(empty_cells)
random_empty_cell["resident"] = 2
return grid, cell_population
def find_neighbor_cells(cell, grid):
"""
Sucht für jede Zelle die 8 umgebenden Nachbarzellen auf dem Grid und
speichert diese im Zellen-Attribut "neighbor-cells".
Das Grid wird als Torus angesehen.
"""
# Anzahl der Zeilen des Grids ermitteln
n_rows = len(grid)
# Anzahl der Spalten bzw. Zellen in einer Zeile des Grids anhand der ersten Zeile ermitteln
n_cols = len(grid[0])
# für jede Zweilenpositionsabweichung
for row_deviation in [-1, 0, 1]:
# für jede Spaltenpositionsabweichung
for col_deviation in [-1, 0, 1]:
# wenn nicht Zeilen- und Spaltenabweichung beide 0 sind
if not (row_deviation == 0 and col_deviation == 0):
# Zeilen- und Spaltenposition der Nachbarzelle berechnen
neighbor_row = (cell["row"] - row_deviation) % n_rows
neighbor_col = (cell["col"] - col_deviation) % n_cols
# Nachbarzelle im grid finden und der betrachteten Zelle in die Liste von Nachbarzellen einfügen
neighbor_cell = grid[neighbor_row][neighbor_col]
cell["neighbor_cells"].append(neighbor_cell)
def get_empty_and_occupied_cells(cell_population):
"""
Gibt eine Liste mit Verweisen auf alle bewohnten und eine Liste mit Verweisen auf alle unbewohnten Zellen aus.
Erwartet eine flache Liste mit allen Zellen.
"""
# Liste für alle unbewohnten Zellen
empty_cells = []
# Liste für alle bewohnten Zellen
occupied_cells = []
# Alle Zellen durchgehen und prüfen, ob Zelle unbewohnt. Dann entsprechender Liste anhängen.
for cell in cell_population:
if cell["resident"] == 0:
empty_cells.append(cell)
else:
occupied_cells.append(cell)
return empty_cells, occupied_cells
def eval_neighborhood(cell):
"""
Berechnet für eine eingegebene Zelle den Anteil an bewohnten Nachbarzellen,
die einen Agenten aus derselben Gruppe beherbergen und speichert diesen im Zellen-Attribut "share_of_same_group".
"""
# Variable zur Zählung der aktuell bewohnten Nachbarzellen
n_neighbors = 0
# Variable zur Zählung der durch Mitglieder derselben Gruppe bewohnte Nachbarzellen
n_neighbors_of_same_group = 0
# für jede Nachbarzelle
for neighbor_cell in cell["neighbor_cells"]:
# wenn Zelle bewohnt, n_neighbors um 1 erhöhen
if neighbor_cell["resident"] != 0:
n_neighbors += 1
# wenn Zelle mit Mitglied derselben Gruppe bewohnt, dann n_neighbors_of_same_group um 1 erhöhen
if neighbor_cell["resident"] == cell["resident"]:
n_neighbors_of_same_group += 1
# Wenn es Nachbarn gibt
if n_neighbors > 0:
# Anteil derselben Gruppe unter Nachbarn berechnen und einspeichern
cell["share_of_same_group"] = n_neighbors_of_same_group / n_neighbors
# ansonten
else:
# "Missing" eintragen
cell["share_of_same_group"] = 999
def run_model(threshold, ticks, ticks_per_snapshot, n_rows=20, n_cols=20, n_group1=190, n_group2=190):
"""
Führt das gesamte Simulationsmodell aus. Hat aktuell noch keinen Output, aber durch Modifikation
könnte ein Dictionary mit relevanten Modell-Informationen ausgegeben werden.
"""
# Grid erstellen
grid, cell_population = create_grid(n_rows, n_cols, n_group1, n_group2)
###############################################
# Simulationsloop
###############################################
# für jeden Zeitschritt
for tick in range(ticks):
# zwei Listen mit allen leeren und bewohnten Zellen erstellen
empty_cells, occupied_cells = get_empty_and_occupied_cells(cell_population)
# eine zufällige Zelle aussuchen
random_cell = random.choice(occupied_cells)
# ausgesuchte Zelle schaut, wie hoch der Anteil der eigenen Gruppe in Nachbarschaft ist
eval_neighborhood(random_cell)
# Wenn in Nachbarschaft zu wenige aus derselben Gruppe wie Agent sind
if random_cell["share_of_same_group"] < threshold:
# zufällige neue, unbewohnte Zelle aussuchen
new_cell = random.choice(empty_cells)
# der neuen Zelle den Agenten zuweisen
new_cell["resident"] = random_cell["resident"]
# den Agenten bei alter Zelle "löschen"
random_cell["resident"] = 0