Hi Manuel:
It appears that the method for computing confidence bands for GLMs in stat_smooth() follows this script:
(i) find the predicted values on the linear predictor scale; call them LPhat;
(ii) compute LPhat +/- 1.96 * se.fit(LPhat)
(iii) apply the inverse link function on the lower and upper CIs.
What stat_smooth() does is to take 80 equally spaced x-values along its range, apply the above algorithm to those x's and then plot the result. We can see whether or not this hypothesis is correct on the kyphosis data. I'm using the version of the kyphosis data in the gam package, which supports the 1990 Hastie and Tibshirani book.
library(gam)
data(kyphosis)
km <- glm(as.numeric(Kyphosis) - 1 ~ Age, data = kyphosis)
# predict.glm() returns a list rather than a data frame
# so we need to do a little work to get the confidence bands
# The plot from your code indicates that at fixed x values,
# the intervals are not necessarily symmetric, which suggests
# some transformation of the limits is performed.
# Get the predictions on the linear predictor scale (default):
kmp <- predict(km, se.fit = TRUE)
# Compute intervals since no 'method =' argument exists in predict.glm():
kmpdf <- data.frame(Age = kyphosis$Age,
lwr = kmp$fit - 1.96 * kmp$se.fit,
upr = kmp$fit + 1.96 * kmp$se.fit)
The y-variable in the plot is the response, not the linear predictor. By definition, in logistic regression, under the canonical link function g() of a response probability p,
g(p) = beta_0 + beta_1 * x1 + beta_2 * x2 + ... + beta_p * xp
The function g() in this case is the canonical logit link function, while the right hand side of the equation is the linear predictor. Life is simplest in this case, because we can then write
p = g^{-1}(linear predictor).
The confidence bands for the probability of positive response p are obtained in stat_smooth() by applying the inverse link function g^{-1} to the upper and lower limits upr and lwr, respectively, in kmpdf:
The canonical link function for logistic regression is the logit function:
logit(p) = log(p/(1 - p))
The inverse link function is the logistic function
logis(x) = exp(x)/(1 + exp(x))
This is what will be applied to lwr and upr:
#----
logis <- function(x) exp(x)/(1 + exp(x))
library(plyr)
kmpdf <- mutate(kmpdf, llim = logis(lwr), ulim = logis(upr))
# Now do the plot:
qplot(Age, as.numeric(Kyphosis) - 1, data = kyphosis) +
stat_smooth(method = "glm", family = "binomial") +
geom_line(data = kmpdf, aes(x = Age, y = llim),
color = "red", linetype = "dashed") +
geom_line(data = kmpdf, aes(x = Age, y = ulim),
color = "red", linetype = "dashed")
#----
The limits should match.
By contrast, another approach would be to compute the predicted values on the response scale and use a Wald-based CI for p, which I think is what Thierry proposed:
kmp2 <- predict(km, type = "response", se.fit = TRUE)
kmpdf2 <- data.frame(Age = kyphosis$Age,
lwr = kmp2$fit - 1.96 * kmp2$se.fit,
upr = kmp2$fit + 1.96 * kmp2$se.fit)
last_plot() +
geom_line(data = kmpdf2, aes(x = Age, y = lwr),
color = "black", linetype = "dotdash") +
geom_line(data = kmpdf2, aes(x = Age, y = upr),
color = "black", linetype = "dotdash")
I'm not going to get into whether which one of these is "right"; in fact, there are other ways (e.g. likelihood-based intervals) one could use. But to answer the question, it appears that stat_smooth() renders intervals that are computed on the linear predictor scale which are then transformed according to the inverse link function. I haven't tried this out with Poisson regression or different link functions in logistic regression to verify that hypothesis - I'll leave that as an exercise.
Finally, note that se.fit on the linear predictor scale (in kmp) is not the same as se.fit on the response scale (in kmp2). This is because the response (under the canonical logit link function) is the inverse link of the linear predictor, so its standard error needs to take into account that transformation - this is where the "delta method" of computing the standard error of a transformed estimator comes into play indirectly. Computationally, the details are taken care of in the GLM fitting algorithm.
HTH,
Dennis