EINFÜHRUNG |
Computersimulationen werden oft dafür verwendet, um ausgehend von einer Zeitaufnahme oder einer gewissen Zeitspanne in der nahen Vergangenheit Voraussagen über das Verhalten eines Systems in der Zukunft zu machen. Solche Prognosen können von grosser strategischer Bedeutung sein und uns beispielsweise in einem Szenario, das zu einer Katastrophe führt, zu rechtzeitigem Umdenken veranlassen. Heute besonders aktuelle Themen sind die Voraussage des Weltklimas und das Bevölkerungswachstum. Unter einer Population versteht man ein System von Individuen, deren Zahl sich auf Grund von inneren Mechanismen, Wechselwirkungen und äusseren Einflüssen in Laufe der Zeit ändert. Sieht man von äusseren Einflüssen ab, so spricht man von einem abgeschlossenen System. Für viele Populationen ist die Veränderung der Populationsgrösse proportional zur aktuellen Grösse der Population. Aus der Zuwachsrate berechnet sich die Veränderung des aktuellen Werts mit: Neuer Wert - alter Wert = alter Wert * Zuwachsrate * Zeitintervall Weil links die Differenz des neuen Werts vom alten Wert steht, nennt man diese Beziehung eine Differenzengleichung. Die Zuwachsrate kann man auch als Zunahmewahrscheinlichkeit pro Individuum und Zeiteinheit auffassen. Ist sie negativ, so nimmt die Grösse der Population ab. Die Zuwachsrate kann sich durchaus im Laufe der Zeit ändern.
|
EXPONENTIELLES WACHSTUM |
Bevölkerungsprognosen sind von grossem Interesse und können politische Entscheidungsprozesse massiv beeinflussen. Jüngstes Beispiel ist die Auseinandersetzung um die Regulierung des Ausländeranteils in der Wohnbevölkerung. Du erhältst vom Bundesamt für Statistik (Quelle: http://www.bfs.admin.ch, Stichwort: STAT-TAB) die Einwohnerzahlen der Schweiz je für das Jahresende 2010 und 2011: 2010: Total z0 = 7 870 134, davon Schweizer s0 = 6 103 857 Kannst du daraus eine Prognose des Ausländeranteils für die nächsten 50 Jahre erstellen? Mit den Zahlen errechnest du zuerst die Zahl der Ausländer a0 = z0 - s0 bzw. a1 = z1 - s1 und damit die jährliche Zuwachsrate zwischen 2010 und 2011 für Schweizer und Ausländer
from gpanel import * # source: Swiss Federal Statistical Office, STAT-TAB z2010 = 7870134 # Total 2010 z2011 = 7954662 # Total 2011 s2010 = 6103857 # Swiss 2010 s2011 = 6138668 # Swiss 2011 def drawGrid(): # Horizontal for i in range(11): y = 2000000 * i line(0, y, 50, y) text(-3, y, str(2 * i)) # Vertical for k in range(11): x = 5 * k line(x, 0, x, 20000000) text(x, -1000000, str(int(x + 2010))) def drawLegend(): setColor("lime green") y = 21000000 move(0, y) draw(5, y) text("Swiss") setColor("red") move(15, y) draw(20, y) text("foreigner") setColor("blue") move(30, y) draw(35, y) text("Total") makeGPanel(-5, 55, -2000000, 22000000) title("Population growth extended") drawGrid() drawLegend() a2010 = z2010 - s2010 # foreigners 2010 a2011 = z2011 - s2011 # foreigners 2011 lineWidth(3) setColor("blue") line(0, z2010, 1, z2011) setColor("lime green") line(0, s2010, 1, s2011) setColor("red") line(0, a2010, 1, a2011) rs = (s2011 - s2010) / s2010 # Swiss growth rate ra = (a2011 - a2010) / a2010 # foreigners growth rate # iteration s = s2011 a = a2011 z = s + a sOld = s aOld = a zOld = z for i in range(0, 49): s = s + rs * s # model assumptions a = a + ra * a # model assumptions z = s + a setColor("blue") line(i + 1, zOld, i + 2, z) setColor("lime green") line(i + 1, sOld, i + 2, s) setColor("red") line(i + 1, aOld, i + 2, a) zOld = z sOld = s aOld = a
|
MEMO |
Wie du aus den Zahlen entnehmen kannst, steigt der Ausländeranteil von 2010 bis 2035, also innert 25 Jahren, auf das Doppelte und in weiteren 25 Jahren auf das Vierfache. Die Populationsgrösse nimmt offenbar bei konstanter Zuwachsrate weit überproportional zu. Bezeichnest du mit T die Verdoppelungszeit, so gilt offenbar mit der Anfangsgrösse A für die Populationsgrösse y nach der Zeit t
Da die Zeit im Exponent steht, nennt man diese rasante Zunahme ein exponentielles Wachstum. |
BEGRENZTES WACHSTUM |
Den experimentellen Verlauf kannst du mit einem Modell verstehen, in dem das vorerst exponentielle Wachstum eine Sättigung erfährt. Dabei lässt du die Zuwachsrate mit zunehmender Populationsgrösse y linear abnehmen, bis sie bei einem bestimmten Sättigungswert m Null wird.
Mit dem Anfangswert y0 = 9.6 mg, der Sättigungsmenge m = 662 mg und der anfänglichen Zuwachsrate r0 = 0.62 /h ergibt sich eine gute Übereinstimmung zwischen Theorie und Experiment. from gpanel import * z = [9.6, 18.3, 29.0, 47.2, 71.1, 119.1, 174.6, 257.3, 350.7, 441.0, 513.3, 559.7, 594.8, 629.4, 640.8, 651.1, 655.9, 659.6, 661.8] def r(y): return r0 * (1 - y / m) r0 = 0.62 y = 9.6 m = 662 makeGPanel(-2, 22, -100, 1100) title("Bacterial growth") drawGrid(0, 20, 0, 1000) lineWidth(2) for n in range(0, 19): move(n, z[n]) setColor("black") fillCircle(0.2) if n > 0: dy = y * r(y) yNew = y + dy setColor("lime green") line(n - 1, y, n, yNew) y = yNew
|
MEMO |
Geht man von einer linearen Abnahme der Zuwachsrate aus, so ergibt sich für die Populationsgrösse eine typische S-kurvenartige Sättigungskurve (auch logistisches Wachstum oder Sigmoide genannt). |
STERBETAFELN |
Ein Mass für die Gesundheit einer Population ist die Wahrscheinlichkeit ein bestimmtes Altersjahr zu überleben bzw. in einem hohen Alter zu sterben. Willst du die Altersverteilung für die Schweizer Bevölkerung untersuchen, so verwendest du wieder aktuelle Daten vom Bundesamt für Statistik und zwar die sogenannten Sterbetafeln (Quelle: http://www.bfs.admin.ch, Stichwort: STAT-TAB) [mehr...
Braucht nichts Makabres zu sein, denn Sterben gehört zum Leben].
Diese enthalten tabellarisch getrennt nach Männern und Frauen die beobachteten Wahrscheinlichkeiten qx und qy, in einem bestimmten Alter zu sterben. Ihre Bestimmung ist grundsätzlich einfach: Man betrachtet am Ende eines Jahres getrennt nach Männern und Frauen alle Todesfälle im vergangenen Jahr und bildet die Häufigkeit der 0-jährigen (gestorben zwischen Geburt und einem Altersjahr), der 1-jährigen, usw. Diese Zahlen teilt man nachher durch die Zahl in dieser Altersgruppe am Anfang des Jahres.
import exceptions from gpanel import * def readData(filename): table = [] fData = open(filename) while True: line = fData.readline().replace(" ", "").replace("'", "") if line == "": break line = line[:-1] # remove trailing \n try: q = float(line) except exceptions.ValueError: break table.append(q) fData.close() return table makeGPanel(-10, 110, -0.1, 1.1) title("Mortality probability (blue -> male, red -> female)") drawGrid(0, 100, 0, 1.0) qx = readData("qx.dat") qy = readData("qy.dat") for t in range(101): setColor("blue") p = qx[t] line(t, 0, t, p) setColor("red") q = qy[t] line(t + 0.2, 0, t + 0.2, q)
|
MEMO |
|
ZEITLICHE ENTWICKLUNG EINER POPULATION |
import exceptions from gpanel import * n = 10000 # size of the population def readData(filename): table = [] fData = open(filename) while True: line = fData.readline().replace(" ", "").replace("'", "") if line == "": break line = line[:-1] # remove trailing \n try: q = float(line) except exceptions.ValueError: break table.append(q) fData.close() return table makeGPanel(-10, 110, -1000, 11000) title("Population behavior/predictions (blue -> male, red -> female)") drawGrid(0, 100, 0, 10000) qx = readData("qx.dat") qy = readData("qy.dat") x = n # males y = n # females for t in range(101): setColor("blue") rx = qx[t] x = x - x * rx line(t, 0, t, x) setColor("red") ry = qy[t] y = y - y * ry line(t + 0.2, 0, t + 0.2, y) |
LEBENSERWARTUNG VON FRAUEN UND MÄNNERN |
In der vorhergehenden Untersuchung wurde nochmals deutlich, dass Frauen länger als Männer leben. Du kannst den Unterschied auch mit einer einzigen Grösse ausdrücken, die man Lebenserwartung nennt. Es handelt sich dabei um den Mittelwert des erreichten Alters. s = Schülerzahl mit Note 1 * 1 + Schülerzahl mit Note 2 * 2 + ... Schülerzahl mit Note 6 * 6 oder allgemeiner: Mittelwert = Summe von (Häufigkeit des Werts * Wert) dividiert durch Totalzahl Wenn du die Häufigkeiten aus einer Häufigkeitsverteilung h der Werte x (hier der Noten 1 bis 6) entnimmst, so nennt man den Mittelwert auch Erwartungswert und du kannst dafür
schreiben. Wie du siehst, werden in der Summe die Häufigkeiten hi mit ihrem Wert xi gewichtet. Die Lebenserwartung ist nichts anderes als der Erwartungswert für das Alter, in dem Frauen bzw. Männer sterben. Um sie mit einer Computersimulation zu berechnen, gehst du von einer bestimmten Grösse von je n = 10000 Männern und Frauen aus und bestimmst die Zahl hx der Männer bzw. hy der Frauen, die im Alter zwischen t und t + 1 sterben. Offenbar lassen sich diese Zahlen aus der Grösse der Populationen x und y zur Zeit t, die du im vorhergehenden Programm berechnet hast, und den Sterberaten rx bzw. ry so ausdrücken: hx = x * rx bzw. hy = y * ry
n = 10000 # size of the population def readData(filename): table = [] fData = open(filename) while True: line = fData.readline().replace(" ", "") if line == "": break line = line[:-1] # remove trailing \n try: q = float(line) except exceptions.ValueError: break table.append(q) fData.close() return table qx = readData("qx.dat") qy = readData("qy.dat") x = n y = n xSum = 0 ySum = 0 for t in range(101): rx = qx[t] x = x - x * rx mx = x * rx # male deaths xSum = xSum + mx * t # male sum ry = qy[t] y = y - y * ry my = y * ry # female deaths ySum = ySum + my * t # female sum print "Male life expectancy:", xSum / 10000 print "Female life expectancy:", ySum / 10000 Mit den Daten der Schweizer Bevölkerung ergeben sich für die Lebenserwartung des Mannes rund 76 Jahre und für diejenige der Frau rund 81 Jahre. |
ALTERSPYRAMIDE |
import exceptions from gpanel import * def readData(filename): table = [] fData = open(filename) while True: line = fData.readline().replace(" ", "").replace("'", "") if line == "": break line = line[:-1] # remove trailing \n try: q = float(line) except exceptions.ValueError: break table.append(q) fData.close() return table def drawAxis(): text(0, -3, "0") line(0, 0, 0, 100) text(0, 103, "100") makeGPanel(-100000, 100000, -10, 110) title("Population pyramid (green -> male, red -> female)") lineWidth(4) zx = readData("zx.dat") zy = readData("zy.dat") for t in range(101): setColor("red") x = zx[t] line(0, t, -x, t) setColor("darkgreen") y = zy[t] line(0, t, y, t) setColor("black") drawAxis()
|
MEMO |
Es ist deutlich der Babyboom in den Jahren 1955 - 1965 (47 - 57 Jährige) zu erkennen. |
VERÄNDERUNG DER ALTERSSTRUKTUR |
Mit einem Tastendruck kannst du immer um ein Jahr vorwärts schalten. import exceptions from gpanel import * k = 2.0 def readData(filename): table = [] fData = open(filename) while True: line = fData.readline().replace(" ", "").replace("'", "") if line == "": break line = line[:-1] # remove trailing \n try: q = float(line) except exceptions.ValueError: break table.append(q) fData.close() return table def drawAxis(): text(0, -3, "0") line(0, 0, 0, 100) text(0, 103, "100") lineWidth(1) for y in range(11): line(-80000, 10* y, 80000, 10 * y) text(str(10 * y)) def drawPyramid(): clear() title("Number of children: " + str(k) + ", year: " + str(year) + ", total population: " + str(getTotal())) lineWidth(4) for t in range(101): setColor("red") x = zx[t] line(0, t, -x, t) setColor("darkgreen") y = zy[t] line(0, t, y, t) setColor("black") drawAxis() repaint() def getTotal(): total = 0 for t in range(101): total += zx[t] + zy[t] return int(total) def updatePop(): global zx, zy zxnew = [0] * 110 zynew = [0] * 110 # getting older and dying for t in range(101): zxnew[t + 1] = zx[t] - zx[t] * qx[t] zynew[t + 1] = zy[t] - zy[t] * qy[t] # making a baby r = k / 20 nbMother = 0 for t in range(20, 40): nbMother += zy[t] zxnew[0] = r / 2 * nbMother zynew[0] = zxnew[0] zx = zxnew zy = zynew makeGPanel(-100000, 100000, -10, 110) zx = readData("zx.dat") zy = readData("zy.dat") qx = readData("qx.dat") qy = readData("qy.dat") year = 2012 enableRepaint(False) while True: drawPyramid() getKeyWait() year += 1 updatePop()
|
MEMO |
Es zeigt sich, dass die Zukunft der Population sehr sensibel von der Zahl k abhängt. Sogar bei k = 2 nimmt sie langfristig ab. Um bei Drücken einer Taste das Bildschirmflackern zu vermeiden, solltest du mit enableRepaint(False) das automatische Rendern abschalten. Die Grafik wird dann in drawPyramid() mit clear() nur im Hintergrundspeicher (offscreen buffer) gelöscht und erst nach der Neuberechnung mit repaint() neu auf dem Bildschirm gerendert. |
AUFGABEN |
|
ZUSATZSTOFF |
RÄUBER-BEUTE-SYSTEME |
Sehr interessant ist das Verhalten von zwei Populationen, die sich in einem bestimmten Ökosystem befinden und sich gegenseitig beeinflussen. Du gehst von folgendem Szenario aus: In einem geschlossenen Gebiet halten sich Hasen und Füchse auf. Die Hasen vermehren sich mit konstanter Zuwachsrate rx. Trifft ein Fuchs auf einen Hasen, so wird er mit der einer bestimmten Wahrscheinlichkeit vom Fuchs gerissen. Die Füchse ihrerseits sterben mit der Sterbewahrscheinlichkeit ry. Ihre Zuwachsrate ist durch den Verzerr von Hasen bestimmt. Wenn man annimmt, dass die Wahrscheinlichkeit, dass sich Füchse und Hasen treffen gleich dem Produkt der Zahl der Hasen x und der Füchse y ist, so ergeben sich zwei Differenzengleichungen für x und y [mehr... Bei diesen Gleichungen handelt es sich um die mathematische Formulierung der Lotka-Volterra-Regeln].
from gpanel import * rx = 0.08 ry = 0.2 gx = 0.002 gy = 0.0004 def dx(): return rx * x - gx * x * y def dy(): return -ry * y + gy * x * y x = 500 y = 20 makeGPanel(-20, 220, -200, 2200) title("Predator-Prey system (red: bunnies, blue: foxes)") drawGrid(0, 200, 0, 2000) lineWidth(2) for n in range(200): xNew = x + dx() yNew = y + dy() setColor("red") line(n, x, n + 1, xNew) setColor("blue") line(n, y, n + 1, yNew) x = xNew y = yNew
|
MEMO |
Die Zahl der Hasen und Füchse schwankt auf und ab. Qualitativ ist dies wie folgt zu verstehen: Da sich die Füchse von den Hasen ernähren, vermehren sich die Füchse dann besonders stark, wenn es viele Hasen gibt. Da dadurch die Population der Hasen dezimiert wird, geht auch die Vermehrung der Füchse zurück. Immerhin steigt trotzdem die Zahl der Hasen (sogar über alle Grenzen). |
AUFGABEN |
|