Chapter 3 Age-Structured Models

3.1 The recipe

3.1.1 Ingredients

For more details on data needs, see XXX, but in brief:

  1. A list of annual survival rates (the fraction of individuals that survive for a year), one for each age. Ideally, this will be survival from one birthday to the next (including from birth to the first birthday). If males and females have different survival rates, list the female values. We will call this list the vector \(\mathbf{p}\), with elements \(p_{(\text{0})}\) (survival probability from birth to age 1), \(p_{(\text{1})}\) (survival probability from age 1 to age 2), \(p_{(\text{2})}\) (survival probability from age 2 to age 3), etc.
  2. A list of age-specific birth rates: For each parental age, the number of offspring per parent (counting both parents), or the number of female offspring produced by each female parent. We will call this list the vector \(\mathbf{b}\), with elements \(b_{(\text{1})}\) (newborns produced by a 1-year-old parent), \(b_{(\text{2})}\) (newborns produced by a 2-year-old parent), etc. Newborns cannot reproduce, so there is no value of \(b_{(\text{0})}\); if the age at first reproduction is less than one, then you will need a shorter timestep.
  3. Identify the maximum age, above which there is no survival. Call this age \(m\); while there may be a non-zero birth rate \(b_{(\text{m})}\), \(m\)-year-olds do not survive to age \(m+1\), so \(p_{(\text{m})} = 0\).

When these are arranged in tabular form, it will look like part of a life table, which you may recall from undergraduate ecology courses. In fact, these two lists provide all the information needed to construct the other columns of the life table (such as the cumulative survivorship, \(l_x\)); but we don’t need those to construct an MPM, so don’t pursue that further.

The viviparous lizard (*Zootoca vivipara*) in the Aamsveen, The Netherlands. CC-BY-SA [Ocrdu](https://commons.wikimedia.org/wiki/User:Ocrdu).

Figure 3.1: The viviparous lizard (Zootoca vivipara) in the Aamsveen, The Netherlands. CC-BY-SA Ocrdu.

The example we will use in this chapter comes from Strijbosch and Creemers (1988), who quantified the age-specific demography of the viviparous lizard (Zootoca vivipara; Fig. 3.1) in an intensive 7-year study on a 1.2 ha plot at the forest reserve “de Hamert” in the Netherlands. The age-specific female birth and survival rates are shown in Table 3.1.

Table 3.1: Age-specific survival and birth rates for the lizard Zootoca vivipara (formerly Lacerta vivipara) in the Netherlands (Strijbosch and Creemers 1988). Age-specific annual survival is calculated from the female cumulative survival values (\(l_x\)) in their Table 6. Age-specific birth rates are calculated by dividing the birth rates in their Table 6 (\(m_x\)) by two, as these appear to represent all offspring, and the primary sex ratio (estimated from two-year-old individuals) did not differ from 1 (pp. 21-22).
Age in years (\(x\)) Female annual survival (\(p_{(\text{x})}\)) Female offspring per female (\(b_{(\text{x})}\))
0 0.424 NA
1 0.726 0.040
2 0.513 1.470
3 0.361 2.065
4 0.175 2.440
5 0.700 3.250
6 0.286 3.250
7 0.000 3.250

3.1.2 Construct the birth matrix, \(\mathbf{B}\)

  1. Make an \(m \times m\) identity matrix (with ones on the diagonal, and zeros everywhere else)
  2. Add an extra row on top, with the birth rates

If \(m=3\), this would look like: \[\begin{equation} \mathbf{B} = \begin{pmatrix} b_{(\text{1})} & b_{(\text{2})} & b_{(\text{3})} \\ 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{pmatrix} \tag{3.1} \end{equation}\]

3.1.3 Construct the survival matrix, \(\mathbf{P}\)

  1. Make an \(m \times m\) matrix with the survival values on the diagonal, and zeros everywhere else
  2. Add an extra column of zeros on the right

If \(m=3\), this would look like: \[\begin{equation} \mathbf{P} = \begin{pmatrix} p_{(\text{0})} & 0 & 0 & 0 \\ 0 & p_{(\text{1})} & 0 & 0 \\ 0 & 0 & p_{(\text{2})} & 0 \end{pmatrix} \end{equation}\]

3.1.4 Combine the birth and survival matrices into the projection matrix

You have two choices here:

  • the postbreeding census model (which we denote \(\mathbf{A_{post}}\)), which takes the population immediately after the breeding season in one year (including the newborns) and projects it to immediately after the breeding season the next year;
  • the prebreeding census model (which we denote \(\mathbf{A_{pre}}\)), which takes the population immediately before the breeding season in one year (so that the youngest individuals are just about to reach their first birthday) and projects it to immediately before the breeding season the next year.

Both versions model the same population; the only difference is when you peek in to see the population abundances. Here are the formulas:

\[\begin{equation} \begin{aligned} \mathbf{A_{post}} &= \mathbf{B} \mathbf{P}\\ \mathbf{A_{pre}} &= \mathbf{P} \mathbf{B} \end{aligned} \end{equation}\]

The formulas look similar, differing only in the order of multiplication. But remember that matrix multiplication is not commutative!

For the \(m=3\) case above, these work out to: \[\begin{equation} \begin{aligned} \mathbf{A_{post}} &= \begin{pmatrix} p_{(\text{0})} b_{(\text{1})} & p_{(\text{1})} b_{(\text{2})} & p_{(\text{2})} b_{(\text{3})} & 0\\ p_{(\text{0})} & 0 & 0 & 0 \\ 0 & p_{(\text{1})} & 0 & 0 \\ 0 & 0 & p_{(\text{2})} & 0 \end{pmatrix} \\ \mathbf{A_{pre}} &= \begin{pmatrix} b_{(\text{1})} p_{(\text{0})} & b_{(\text{2})} p_{(\text{0})} & b_{(\text{3})} p_{(\text{0})} \\ p_{(\text{1})} & 0 & 0 \\ 0 & p_{(\text{2})} & 0 \end{pmatrix} \end{aligned} \tag{3.2} \end{equation}\]

3.2 Example

Let’s apply this to the lizard life table in Table 3.1. This model is large enough that I don’t want to calculate it by hand, so I’ll use R. First, enter the age-specific survival and birth rates, and the maximum age:

Notice that the first element of px is \(p_{(\text{0})}\), whereas the first element of bx is \(b_{(\text{1})}\). Thus, px doesn’t have the zero survival of 7-year-olds, and bx doesn’t have the zero birth rate of newborns. If you are working with a dataset that includes these zeros, you’ll need to trim them off before moving to the next step.

Now construct the birth matrix, \(\mathbf{B}\). A useful function in R is diag(), the diagonal function. If m is a scalar (a single number), then diag(m) creates an \(m \times m\) matrix with ones on the diagonal and zeros everywhere else. Also, recall that rbind() (“row bind”) adds the second argument below the first argument.

##    [,1] [,2]  [,3] [,4] [,5] [,6] [,7]
## bx 0.04 1.47 2.065 2.44 3.25 3.25 3.25
##    1.00 0.00 0.000 0.00 0.00 0.00 0.00
##    0.00 1.00 0.000 0.00 0.00 0.00 0.00
##    0.00 0.00 1.000 0.00 0.00 0.00 0.00
##    0.00 0.00 0.000 1.00 0.00 0.00 0.00
##    0.00 0.00 0.000 0.00 1.00 0.00 0.00
##    0.00 0.00 0.000 0.00 0.00 1.00 0.00
##    0.00 0.00 0.000 0.00 0.00 0.00 1.00

Although it’s larger, this matrix has the same structure as Eq. ((3.1)).

One quirk of R is that, while the columns are labeled with the index of the columns (which is what we expect for a generic matrix), the first row is labeled “bx” and the rest of the rows are unlabeled. The labels don’t actually matter for the rest of the calculations, but they will result in the final matrices having uninformative row labels. If you don’t like this, you can reset the row labels with the command rownames(B) <- NULL. Alternatively, you can use this slightly more complex command (it also does both steps at once):

##      [,1] [,2]  [,3] [,4] [,5] [,6] [,7]
## [1,] 0.04 1.47 2.065 2.44 3.25 3.25 3.25
## [2,] 1.00 0.00 0.000 0.00 0.00 0.00 0.00
## [3,] 0.00 1.00 0.000 0.00 0.00 0.00 0.00
## [4,] 0.00 0.00 1.000 0.00 0.00 0.00 0.00
## [5,] 0.00 0.00 0.000 1.00 0.00 0.00 0.00
## [6,] 0.00 0.00 0.000 0.00 1.00 0.00 0.00
## [7,] 0.00 0.00 0.000 0.00 0.00 1.00 0.00
## [8,] 0.00 0.00 0.000 0.00 0.00 0.00 1.00

Even better, give the matrix informative row and column names. The columns represent the parents, so we would want to label the columns “age 1”, “age 2”, etc. The first row represents the newborns (age zero), and the rest of the rows are still the parents (who haven’t aged, as we are assuming that the breeding season is very short), so we want to label the rows “age 0”, “age 1”, “age 2”, etc. We set the column and row names using the R functions colnames() and rownames(), respectively. The other trick is to use the paste() command to generate an appropriate character vector: for example, paste("age", 1:3) generates the character vector "age 1", "age 2", "age 3".

##       age 1 age 2 age 3 age 4 age 5 age 6 age 7
## age 0  0.04  1.47 2.065  2.44  3.25  3.25  3.25
## age 1  1.00  0.00 0.000  0.00  0.00  0.00  0.00
## age 2  0.00  1.00 0.000  0.00  0.00  0.00  0.00
## age 3  0.00  0.00 1.000  0.00  0.00  0.00  0.00
## age 4  0.00  0.00 0.000  1.00  0.00  0.00  0.00
## age 5  0.00  0.00 0.000  0.00  1.00  0.00  0.00
## age 6  0.00  0.00 0.000  0.00  0.00  1.00  0.00
## age 7  0.00  0.00 0.000  0.00  0.00  0.00  1.00

Now construct the survival matrix, \(\mathbf{P}\). We will again use diag(), but in a different way. If px is a vector with length \(m\), then diag(px) creates an \(m \times m\) matrix with the values of px on the diagonal and zeros everywhere else. Also, recall that cbind() (“column bind”) adds the second argument to the right the first argument.

##       [,1]  [,2]  [,3]  [,4]  [,5] [,6]  [,7] [,8]
## [1,] 0.424 0.000 0.000 0.000 0.000  0.0 0.000    0
## [2,] 0.000 0.726 0.000 0.000 0.000  0.0 0.000    0
## [3,] 0.000 0.000 0.513 0.000 0.000  0.0 0.000    0
## [4,] 0.000 0.000 0.000 0.361 0.000  0.0 0.000    0
## [5,] 0.000 0.000 0.000 0.000 0.175  0.0 0.000    0
## [6,] 0.000 0.000 0.000 0.000 0.000  0.7 0.000    0
## [7,] 0.000 0.000 0.000 0.000 0.000  0.0 0.286    0

Again, we add row and column names. Here, the columns represent the ages right at the end of the breeding season (ages 0 through \(m\)), whereas the rows represents the ages at the beginning of the next breeding season a year later (ages 1 through \(m\)):

##       age 0 age 1 age 2 age 3 age 4 age 5 age 6 age 7
## age 1 0.424 0.000 0.000 0.000 0.000   0.0 0.000     0
## age 2 0.000 0.726 0.000 0.000 0.000   0.0 0.000     0
## age 3 0.000 0.000 0.513 0.000 0.000   0.0 0.000     0
## age 4 0.000 0.000 0.000 0.361 0.000   0.0 0.000     0
## age 5 0.000 0.000 0.000 0.000 0.175   0.0 0.000     0
## age 6 0.000 0.000 0.000 0.000 0.000   0.7 0.000     0
## age 7 0.000 0.000 0.000 0.000 0.000   0.0 0.286     0

Finally, we use matrix multiplication to get the projection matrices. In R, matrix multiplication is indicated with the compound symbol %*% (if you just used * then it would do element-by-element multiplication, which is mathematically very different).

##         age 0   age 1    age 2   age 3   age 4 age 5  age 6 age 7
## age 0 0.01696 1.06722 1.059345 0.88084 0.56875 2.275 0.9295     0
## age 1 0.42400 0.00000 0.000000 0.00000 0.00000 0.000 0.0000     0
## age 2 0.00000 0.72600 0.000000 0.00000 0.00000 0.000 0.0000     0
## age 3 0.00000 0.00000 0.513000 0.00000 0.00000 0.000 0.0000     0
## age 4 0.00000 0.00000 0.000000 0.36100 0.00000 0.000 0.0000     0
## age 5 0.00000 0.00000 0.000000 0.00000 0.17500 0.000 0.0000     0
## age 6 0.00000 0.00000 0.000000 0.00000 0.00000 0.700 0.0000     0
## age 7 0.00000 0.00000 0.000000 0.00000 0.00000 0.000 0.2860     0
##         age 1   age 2   age 3   age 4 age 5 age 6 age 7
## age 1 0.01696 0.62328 0.87556 1.03456 1.378 1.378 1.378
## age 2 0.72600 0.00000 0.00000 0.00000 0.000 0.000 0.000
## age 3 0.00000 0.51300 0.00000 0.00000 0.000 0.000 0.000
## age 4 0.00000 0.00000 0.36100 0.00000 0.000 0.000 0.000
## age 5 0.00000 0.00000 0.00000 0.17500 0.000 0.000 0.000
## age 6 0.00000 0.00000 0.00000 0.00000 0.700 0.000 0.000
## age 7 0.00000 0.00000 0.00000 0.00000 0.000 0.286 0.000

Notice that the row and column names that we set for the B and P matrices propagated through automatically, so that the first row and column of the postbreeding model represents newborns (“age 0”), whereas in the prebreeding census model the first row and column represents age 1 (the youngest individuals are just about to have their first birthday).

If you work through the numbers, you’ll see that these match the structure of the post-breeding and pre-breeding matrices in Eq. (3.2).

In theory, these two matrices should have exactly the same asymptotic growth rate, \(\lambda\). Lets use the lambda() function in the popbio package to check this:

## [1] 0.9986679
## [1] 0.9986679

Yup, they match!

We will want to use this model later in the book, so package it up into a list for easy access:

3.3 Why use this recipe?

Now, these matrices don’t look that complex; why didn’t I tell you how to construct them directly, rather than constructing the intermediate birth and survival matrices? Look at the matrix elements on the top row of each matrix; these are called the fertility coefficients, and represent the reproductive component of the model. Look at how they are constructed from survival and birth rates: does this make sense to you? If it does not, don’t worry: it is not an implementation of biological intuition, but instead a bunch of bookkeeping. But first I would need to convince you that these are the right formulas; and then I would need to look over your shoulder and remind you to use them each time you constructed a model, because, like double-entry bookkeeping, it is easy to forget what to do unless you do it often.

3.4 Extensions, caveats, and assumptions

3.4.1 No maximum age

The recipe and example above describes a classic Leslie matrix model, in which there is a well-defined maximum age at which all individuals die. In many species, however, individuals may survive more-or-less indefinitely; above a certain age, it might be biologically reasonable to assume that all individuals have the same birth and survival rates, independent of age. Even if there is not strong evidence to support that assumption, there may be so few old individuals in the population that it is impossible to estimate separate demographic rates for each age class. In this case, we can augment the Leslie model by adding an “old individual” stage; while this technically becomes a stage-structured model, it is such a common modification to age structured models that we include it here.

Now, instead of \(m\) being the maximum age, we can write \(m+\) to represent the class of individuals age \(m\) and above. They have a non-zero survival, so the vector of survival values now has \(m+1\) values (\(p_{(\text{0})}, p_{(\text{1})}, \dots, p_{(\text{m-1})}, p_{(\text{m+})}\)). The only modification to the recipe above is to put the value of \(p_{(\text{m+})}\) into the bottom-right element of the \(\mathbf{P}\) matrix. All else proceeds as above.

3.4.2 Post-reproductive ages

In many animal species, individuals may survive beyond their maximum age of reproduction. These post-reproductive age classes have birth rates of zero, and the resulting projection matrix may be problematic for certain sorts of analyses. There is no problem with using the matrix to numerically simulate the age-structured population through time. However, analyses that require calculating the eigenvalues and eigenvectors of the matrix, such as the asymptotic population growth rate, \(\lambda\), and the sensitivity of \(\lambda\) to matrix elements, might generate mysterious errors (depending on the software being used). If this occurs, you can simply delete the rows and columns of the projection matrix that are associated with the post-reproductive ages, and re-do the analysis. Because population growth is unaffected (at least in simple density-independent models such as these) by the survival of post-reproductive ages, you can set those sensitivity values to zero after analyzing the remainder of the matrix.

3.4.3 Extended breeding season

In describing the recipe above, I have made some potentially troubling assumptions. To be clear, these assumptions are embedded in the “standard” approach to constructing MPMs; the use of seasonal matrices merely makes them more apparent.

The first such assumption is that the breeding season is “instantaneous,” such that there is no mortality during the season and all individuals in a cohort are exactly the same age. This is the standard assumption in the “birth-pulse” models that we are describing here. If reproduction occurs continuously throughout the year, without seasonal variation, then there is a “birth-flow” formalism that approximates this. I don’t treat that here, as truly aseasonal reproduction is vanishingly rare in the wild, and in the literature I have only seen birth-flow models applied to human and laboratory populations. However, it would be possible to extend the breeding season component of the model to extend to a finite duration, during which both parents and offspring might die, and in which first-year survival of offspring might depend on when in the breeding season they were born. I will explore this in a subsequent chapter.

3.4.4 Dependent offspring

Another potentially important feature of many animals’ life history is an extended period when offspring are dependent on their parents for food and protection. In such a situation, the death of the parent may lead to reduced (or zero) survival for the offspring. The standard age-structured MPM, as we have developed above, does not account for this. If the dependence lasts for a full year (or more), this can be addressed by creating a special class for “mothers with offspring,” as was done by Fujiwara and Caswell (2001) in their model for the North Atlantic right whale. For shorter periods of parental care, we could create a post-birth “dependency season” during which the fates of parents and offspring are correlated.

A related issue arises with extended gestation periods, creating a pre-birth dependency season. Furthermore, if pregnancy affects maternal survival, we could explicitly distinguish pregnant and non-pregnant females during that season, allowing the model to incorporate trade-offs between survival and reproduction.

I will address these issues in a subsequent chapter.

3.4.5 Individual heterogeneity

Finally, the model assumes that all individuals of a given age have the same birth and death rates. Violation of this assumption creates “unmodeled heterogeneity,” and might affect the predictions of your model, depending on the nature of the heterogeneity and the way you are using the model. Both the identification of such heterogeneity and the consequences are ongoing areas of research; I won’t provide a general treatment in this book, but will touch on it in certain points where it commonly arises.

References

Fujiwara, M., and H. Caswell. 2001. “Demography of the endangered North Atlantic right whale.” Nature 414: 537–41.

Strijbosch, H., and R. C. M. Creemers. 1988. “Comparative demography of sympatric populations of Lacerta vivipara and Lacerta agilis.” Oecologia 76: 20–26.