I wish to compute the effective sample size (ESS) for a posterior sample of size $M$. I have looked at several documentations (e.g. WinBUGS p11; Stan sec 15.4) and several other Stack Exchange questions (e.g. this and this). There seems to be several variations of definitions of variance (what correction to use in denominator), autocorrelation, and ESS formulas. I have tried many variations, but none of them match the results from effectiveSize()
. At the 'top-level', the first 2 sources concur that the formula for ESS is:
$$ESS=\frac{M}{1+2\sum_{k=1}\rho_k}$$
although variants exist, such as here, suggesting it should be $|\rho|$, and here, suggesting a completely different variant:
$$ESS=M\frac{\lambda^2}{\sigma^2}, ~~~\text{ where } \sigma^2 = \lambda^2 + 2\sum_{k=1}\rho_k \text{ and } \lambda^2 = \text{var}(x)$$
where $x$ is a vector representing an estimate of a parameter at each MCMC iteration. Then there is the issue of how the autocorrelation, $\rho$, is calculated. This suggests:
$$\rho_k = \frac{\text{cov}[x_t, x_{t+k}]}{\text{var}[x_t]}$$
where $\text{var}[x_t]$ could have a denominator of $M$ or $M-1$. But most sources just describe $\rho$ without giving an explicit formula, e.g. "...$\rho_k$ is the lag $k$ autocorrelation for one parameter..." link.
I'm not even confident about the expressions for $x_t$ and $x_{t+k}$. My understanding is
$$x_t = \{x_1,x_2,\ldots,x_{M-k}\}$$ $$x_{t+k} = \{x_{k+1},x_{k+2},\ldots,x_M\}$$
I can compute the ESS in R using the coda
package easily enough:
coda::effectiveSize(x)
But I want to understand how this is computed.
So what is the correct definition of the ESS?
For clarity, I have provided R code (updated for new variant) which attempts to demonstrate the lack of agreement.
Here is a user-defined R function which computes several variations of rho
($\rho$) and the ESS formula:
get.ESS <- function(x, autocor = 1, ESS = 1){
M <- length(x)
# Re-centre at zero
x <- x - mean(x)
# Autocorrelations
rho <- rep(NA, M-2)
for(lag in 0:(M-2)){
# Split time-series in two, separated by 'lag'
theta.1 <- x[1:(M-lag)]
theta.2 <- x[(1+lag):M]
# Autocorrelation
if(autocor %in% c(1, 4)){
rho[lag + 1] <- cor(theta.2, theta.1)
}else if(autocor == 2){
rho[lag + 1] <- mean(theta.1 * theta.2) / var(x)
}else if(autocor == 5){
rho[lag + 1] <- cov(theta.2, theta.1)
}
}
if(autocor == 3){
rho <- stats::acf(x = x, lag.max = M-2, plot = FALSE)$acf
}else if(autocor == 4){
# 'Relative' autocorrelation
rho <- rho * (M - 0:(M-2)) / M
}
# Effective sample size
if(ESS == 1){
E <- M / (1 + 2 * sum(rho))
}else if(ESS == 2){
E <- M / (1 + 2 * sum(abs(rho)))
}else if(ESS == 3){ # To be used with autocor = 5
lambda.sq <- M * var(x)
sigma.sq <- lambda.sq + 2 * sum(rho)
E <- M * lambda.sq / sigma.sq
}
return(E)
}
The arguments autocor
and ESS
set the variation to be computed. Results:
M <- 300 # Number of MCMC iterations
set.seed(1)
x <- rnorm(M, 0, 1)
get.ESS(x, 1, 1) # -178.352
get.ESS(x, 2, 1) # 153.4736
get.ESS(x, 3, 1) # 150.1211
get.ESS(x, 4, 1) # 149.9286
get.ESS(x, 5, 1) # 367.5048
get.ESS(x, 1, 2) # 5.553791
get.ESS(x, 2, 2) # 6.272066
get.ESS(x, 3, 2) # 14.85799
get.ESS(x, 4, 2) # 14.65066
get.ESS(x, 5, 2) # 6.524995
# Compare with:
coda::effectiveSize(x) # 300 = M
As you can see, these aren't even close to being correct. The help file on effectiveSize
wasn't very helpful on how they compute it.
So what is the correct effective sample size (ESS) calculation (at least that which is used by effectiveSize
)?
Update:
Using the variant suggested here, i.e. $ESS=M\frac{\lambda^2}{\sigma^2}$:
get.ESS(x, 1, 3) # 300.0289
get.ESS(x, 2, 3) # 299.9897
get.ESS(x, 3, 3) # 299.9893
get.ESS(x, 4, 3) # 299.9892
get.ESS(x, 5, 3) # 300.1979 - the actual definition proposed
The results seem correct, regardless of the variant of $\rho$ (which is strange). Using a highly correlated sample for $x$ instead of white noise shows similar values (300 or larger), which is clearly wrong - it should reduce as correlation increases. So the question still stands.