kd_2dt <- function(r, a, p) (2 * p * r / a^2) * (1 + r^2 / a^2)^(-(p + 1))
m_2dt <- function(a, p) if (is.na(p)) NA else if (p > 0.5) p * a * (sqrt(pi) / 2) * gamma(p - 0.5) / gamma(p + 1) else Inf
med_2dt <- function(a, p) a * sqrt(2^(1 / p) - 1)
fit_2dt <- function(r) {
nll <- function(v) { d <- kd_2dt(r, exp(v[1]), exp(v[2])); -sum(log(pmax(d, 1e-300))) }
o <- tryCatch(optim(c(log(median(r)), 0), nll, method = "BFGS"),
error = function(e) optim(c(log(median(r)), 0), nll, method = "Nelder-Mead"))
list(a = exp(o$par[1]), p = exp(o$par[2])) }
set.seed(303)
a_true <- 20; p_true <- 0.85; n <- 500
r <- a_true * sqrt((1 - runif(n))^(-1 / p_true) - 1) # heavy tail: mean finite, variance infinite
f <- fit_2dt(r)
samp_mean <- mean(r); samp_med <- median(r); samp_max <- max(r)The mean dispersal distance
Ask how far a species disperses and the answer usually comes back as one number: the mean dispersal distance. It goes into spread-rate formulas, into connectivity metrics, into comparisons across species. It is also, for the fat-tailed kernels that dispersal data tend to favour, one of the least trustworthy numbers you can compute, because the mean is an average over the entire tail, including the part no trap ever caught. This tutorial takes the mean apart.
The mean lives in the tail
Start from the 2Dt kernel, whose distance density and survival function are
\[ k_D(r) = \frac{2p\,r}{a^2}\left(1 + \frac{r^2}{a^2}\right)^{-(p+1)}, \qquad P(R > r) = \left(1 + \frac{r^2}{a^2}\right)^{-p}. \]
The tail falls like a power law, r^{-(2p+1)}, and the exponent p controls how heavy it is. That exponent also decides whether the mean and variance exist at all. Working through the integrals, the mean \int_0^\infty r\,k_D(r)\,dr is finite only when p > 1/2, and the variance only when p > 1. Below those thresholds the moment is infinite: not large, infinite.
The fitted kernel has p = 0.95 and scale 21.6 m. The seeds have a sample median of 22.1 m, a sample mean of 35.6 m, and a single furthest seed at 692 m. The mean sits well above the median because the far seeds pull it up, and the fitted p of 0.95 is close enough to 1 that the variance is barely finite.
How sensitive is the mean to that exponent? Hold the fitted scale fixed and vary p.
p_grid <- c(0.6, 0.7, 0.85, 1.0, 1.5)
mean_grid <- sapply(p_grid, function(pp) m_2dt(f$a, pp))
med_grid <- sapply(p_grid, function(pp) med_2dt(f$a, pp))
names(mean_grid) <- names(med_grid) <- p_grid
mean_span <- max(mean_grid) / min(mean_grid)
med_span <- max(med_grid) / min(med_grid)Across that range the mean of the fitted kernel runs from 122 m down to 22 m, a factor of 5.7, and it heads to infinity as p approaches 1/2. The median moves from 32 m to 17 m over the same range, a factor of only 1.9, and it stays finite everywhere. The mean is a tail quantity; the median is a bulk quantity.
Not just sensitive: unidentified
Sensitivity to p would be harmless if p were pinned down. It is not. Bootstrap the fit and look at where the tail exponent lands.
set.seed(3033)
B <- 400
bp <- replicate(B, { rs <- sample(r, n, replace = TRUE)
tryCatch(fit_2dt(rs)$p, error = function(e) NA_real_) })
bp <- bp[is.finite(bp) & bp < 50] # is.finite is not enough: drop the rare resample where the optimiser fails to converge and the tail exponent runs off to a huge (but finite) value
p_ci <- quantile(bp, c(0.025, 0.975))
frac_infvar <- mean(bp <= 1) # fraction of fits with infinite variance
med_boot <- sapply(bp, function(pp) med_2dt(f$a, pp))
cv_med <- 100 * sd(med_boot) / mean(med_boot)The tail exponent’s 95% bootstrap interval is 0.82 to 1.18, straddling the value p = 1 where the variance stops existing. In fact 70 percent of the resampled fits fall below p = 1, so more often than not the fitted kernel has no finite variance, and the standard error of the mean dispersal distance is not a well-defined quantity to begin with. That poorly resolved exponent is exactly what the mean depends on most: the figure above shows the mean climbing steeply as p falls, so the uncertainty the data cannot resolve lands squarely on the mean. The median is a flat function of the same parameter, and its bootstrap coefficient of variation is a tame 6 percent.
When the mean does not exist at all
The sharpest version of the problem is easy to miss, because the software never complains. Simulate from a heavier tail, p = 0.45, for which the population mean is infinite.
set.seed(3037)
r_heavy <- 20 * sqrt((1 - runif(2000))^(-1 / 0.45) - 1) # 2Dt, p = 0.45: population mean does not exist
pop_mean <- m_2dt(20, 0.45) # analytic population mean
stopifnot(is.infinite(pop_mean)) # it is infinite
emp_mean <- mean(r_heavy) # sample mean: a finite number
emp_med <- median(r_heavy)The population mean is infinite. The sample mean of two thousand draws is 162 m: a finite, ordinary-looking number that an analysis would report without hesitation, and that estimates nothing, because there is nothing finite to estimate. Draw a new sample and it lands somewhere else entirely, with no tendency to settle. The median, by contrast, is 36 m and behaves. The lesson is not that dispersal means are always infinite; it is that a finite sample mean is no evidence that the population mean exists.
The running average makes this visible. For the heavy-tailed data the cumulative mean lurches upward each time a new record-far seed arrives and never converges; the cumulative median walks steadily to its limit.
What to report
The median dispersal distance, or a fixed within-data quantile such as the distance containing 90 percent of seeds, is anchored to the bulk of the data and stays stable whether the tail is thin or fat. The mean is not: it averages over a tail the traps barely sampled, it swings with the least-identified parameter in the fit, and for a genuinely heavy kernel it does not exist while still returning a plausible number. Report the mean if a spread model needs it, but report it with the tail exponent beside it and treat it as a modelled extrapolation, not a measurement. The final tutorial in this cluster turns these observations into a short set of checks you can run on any fitted kernel.
References
Kot M, Lewis MA, van den Driessche P 1996. Ecology 77(7):2027-2042 (10.2307/2265698).
Clark JS 1998. American Naturalist 152(2):204-224 (10.1086/286162).
Nathan R, Klein E, Robledo-Arnuncio JJ, Revilla E 2012. In: Clobert J et al. (eds) Dispersal Ecology and Evolution, Oxford University Press, pp 187-210. ISBN 978-0-19-960889-8.