The Price equation in R

evolutionary ecology
social evolution
quantitative genetics
R
ecology tutorial
Decompose evolutionary change in R with the Price equation: selection as a covariance plus a transmission term, an exact identity that underlies kin selection.
Author

Tidy Ecology

Published

2026-08-06

Most of evolutionary biology is bookkeeping: how much did a trait mean move in one generation, and why. The Price equation (Price 1970) is the exact accounting identity for that move. It splits the change into a part due to selection, written as a covariance between fitness and the trait, and a part due to imperfect transmission from parent to offspring. It is not a model with assumptions to check; it is an algebraic identity, true for any population, and it is the foundation the kin selection results are built on. This post derives it numerically in base R.

The identity

For a population of parents with trait value z and fitness w (number of offspring), and a transmission change delta for each parent’s offspring, the change in the mean trait is

\[ \bar{w}\,\Delta\bar{z} = \operatorname{Cov}(w, z) + \operatorname{E}(w\,\delta). \]

The first term is selection: if fitness covaries with the trait, the mean shifts. The second is transmission: if offspring differ systematically from parents (mutation, biased inheritance, developmental drift), that shifts the mean too. Here is a population where the trait raises fitness but offspring drift downward from their parents.

set.seed(439)
n <- 2000
z <- rnorm(n, 10, 2)
w <- pmax(0, 1 + 0.25 * (z - 10) + rnorm(n, 0, 0.5))   # fitness rises with z
delta <- rnorm(n, -0.3, 0.4)                            # offspring drift below parents

zbar <- mean(z); wbar <- mean(w)
dz_obs   <- sum(w * (z + delta)) / sum(w) - zbar        # actual change in the mean
selection    <- mean((w - wbar) * (z - zbar)) / wbar    # Cov(w, z) / wbar
transmission <- mean(w * delta) / wbar                  # E(w delta) / wbar
cat(sprintf("observed change    = %.5f\n", dz_obs))
observed change    = 0.51543
cat(sprintf("selection + transmission = %.5f\n", selection + transmission))
selection + transmission = 0.51543
cat(sprintf("difference = %.1e\n", dz_obs - (selection + transmission)))
difference = -9.7e-15

The two sides agree to machine precision: the difference is 1e-15, which is zero in floating point. That exactness is the point. The Price equation does not approximate the change; it partitions it. Any evolutionary change, in any population, splits cleanly into these two pieces.

Reading the two terms

The split is informative on its own. Here the selection term is 0.816 and the transmission term is -0.300.

cat(sprintf("selection term    = %+.4f\n", selection))
selection term    = +0.8158
cat(sprintf("transmission term = %+.4f\n", transmission))
transmission term = -0.3004
cat(sprintf("net change        = %+.4f\n", selection + transmission))
net change        = +0.5154

Selection is pushing the trait up hard, but downward transmission is bleeding off more than a third of that gain. A trait can be under strong positive selection and still barely move, or move backwards, if transmission opposes it. This is why measuring selection alone (a covariance with fitness) does not tell you how a population will evolve; you also need to know how faithfully the trait is passed on. It is the same lesson the breeder’s equation teaches with heritability, here in its most general form.

library(ggplot2)
d <- data.frame(part = factor(c("selection", "transmission", "net change"),
                              levels = c("selection", "transmission", "net change")),
                val = c(selection, transmission, selection + transmission))
ggplot(d, aes(part, val, fill = part)) +
  geom_col(width = 0.6) +
  geom_hline(yintercept = 0, colour = "#46604a", linewidth = 0.4) +
  scale_fill_manual(values = c(selection = "#275139", transmission = "#b5534e", "net change" = "#c9b458"),
                    guide = "none") +
  labs(x = NULL, y = "Contribution to change in trait mean") +
  theme_minimal(base_size = 12)
A bar chart showing a large positive selection bar, a negative transmission bar, and their smaller positive sum.
Figure 1: The observed change in the trait mean is the sum of a selection term (fitness covaries with the trait) and a transmission term (offspring drift below parents). Downward transmission cancels part of the selective gain.

Why it matters

The Price equation earns its keep when the transmission term is itself hiding structure. If offspring fitness depends on a relative’s trait, the transmission term becomes a second covariance, and the whole equation becomes Hamilton’s rule (Queller 1992). The same identity that separates selection from transmission separates direct selection on an individual from the selection it experiences through its kin. It also underlies the selection effect in biodiversity experiments, which is a Price covariance between yield and monoculture performance. The equation is a lens that reappears wherever change needs to be partitioned.

An honest limit

Being an identity is a strength and a limitation. The Price equation is always true, so it never tells you whether your fitness measure is the right one, whether the covariance is causal, or whether the transmission term is mechanism or noise. It reorganises what you measured; it does not validate it. A covariance between fitness and a trait is consistent with the trait causing fitness, with an unmeasured trait causing both, or with reverse causation, exactly as any regression is. Use the Price equation to see the structure of change clearly, then bring biology to decide what the terms mean.

References

Price GR 1970. Nature 227(5257):520-521 (10.1038/227520a0)

Price GR 1972. Annals of Human Genetics 35(4):485-490 (10.1111/j.1469-1809.1957.tb01874.x)

Queller DC 1992. Evolution 46(2):376-380 (10.1111/j.1558-5646.1992.tb02045.x)

Frank SA 1998. Foundations of Social Evolution. Princeton University Press. ISBN 978-0691059341

Newsletter

Get new tutorials by email

New R and QGIS tutorials for ecologists, straight to your inbox. No spam; unsubscribe anytime.

By subscribing you agree to receive these emails and confirm your address once. See the privacy policy.