Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/notebooks/rabbits.ipynb
Views: 531
Modeling and Simulation in Python
Rabbit example
Copyright 2017 Allen Downey
This notebook develops a simple growth model, like the ones in Chapter 3, and uses it to demonstrate a parameter sweep.
The system we'll model is a rabbit farm. Suppose you start with an initial population of rabbits and let them breed. For simplicity, we'll assume that all rabbits are on the same breeding cycle, and we'll measure time in "seasons", where a season is the reproductive time of a rabbit.
If we provide all the food, space and other resources a rabbit might need, we expect the number of new rabbits each season to be proportional to the current population, controlled by a parameter, birth_rate
, that represents the number of new rabbits per existing rabbit, per season. As a starting place, I'll assume birth_rate = 0.9
.
Sadly, during each season, some proportion of the rabbits die. In a detailed model, we might keep track of each rabbit's age, because the chance of dying is probably highest for young and old rabbits, and lowest in between. But for simplicity, we'll model the death process with a single parameter, death_rate
, that represent the number of deaths per rabbit per season. As a starting place, I'll assume death_rate = 0.5
.
Here's a system object that contains these parameters as well as:
The initial population,
p0
,The initial time,
t0
, andThe duration of the simulation,
t_end
, measured in seasons.
Here's a version of run_simulation, similar to the one in Chapter 3, with both births and deaths proportional to the current population.
Now we can run the simulation and display the results:
Notice that the simulation actually runs one season past t_end
. That's an off-by-one error that I'll fix later, but for now we don't really care.
The following function plots the results.
And here's how we call it.
Let's suppose our goal is to maximize the number of rabbits, so the metric we care about is the final population. We can extract it from the results like this:
And call it like this:
To explore the effect of the parameters on the results, we'll define make_system
, which takes the system parameters as function parameters(!) and returns a System
object:
Now we can make a System
, run a simulation, and extract a metric:
To see the relationship between birth_rate
and final population, we'll define sweep_birth_rate
:
The first parameter of sweep_birth_rate
is supposed to be an array; we can use linspace
to make one.
Now we can call sweep_birth_rate
.
The resulting figure shows the final population for a range of values of birth_rate
.
Confusingly, the results from a parameter sweep sometimes resemble a time series. It is very important to remember the difference. One way to avoid confusion: LABEL THE AXES.
In the following figure, the x-axis is birth_rate
, NOT TIME.
The code to sweep the death rate is similar.
And here are the results. Again, the x-axis is death_rate
, NOT TIME.
In the previous sweeps, we hold one parameter constant and sweep the other.
You can also sweep more than one variable at a time, and plot multiple lines on a single axis.
To keep the figure from getting too cluttered, I'll reduce the number of values in birth_rates
:
By putting one for loop inside another, we can enumerate all pairs of values.
The results show 4 lines, one for each value of birth_rate
.
(I did not plot the lines between the data points because of a limitation in plot
.)
If you suspect that the results depend on the difference between birth_rate
and death_rate
, you could run the same loop, plotting the "net birth rate" on the x axis.
If you are right, the results will fall on a single curve, which means that knowing the difference is sufficient to predict the outcome; you don't actually have to know the two parameters separately.
On the other hand, if you guess that the results depend on the ratio of the parameters, rather than the difference, you could check by plotting the ratio on the x axis.
If the results don't fall on a single curve, that suggests that the ratio alone is not sufficient to predict the outcome.