悍

Where you are likely confused is in the difference between confidence and prediction interval. Confidence intervals, which are used in geom_smooth are the predicted confidence in the estimated mean. This is a measure of how far the average of your observations will deviate at the point estimate. In predict.lm there is an option to add interval = "prediction", which would give you the prediction interval. The prediction interval incorporates the uncertainty in the error-term from y ~ x %*% beta + epsilon, while the confidence interval only incorporates the fixed effect uncertainty from y ~ x %*% beta. I have not looked into prediction intervals for loess curves, and other non- and semi-parametric smoothers, but it does not seem to be implemented in ?predict.loess
We can illustrate how geom_smooth estimates the confidence intervals by manual calculation. Lets start by using the most boring reproducible example. mtcars from the stats package (included in base R).
data(mtcars)
fit <- loess(mpg ~ hp, data = mtcars)
preds <- predict(fit, se = TRUE)
names(preds)
#[1] "fit" "se.fit" "residual.scale" "df"
To calculate the confidence interval, we use the standard formula as you correctly specified.
T <- qt(p = 0.975, df = preds$df)
lwr <- preds$fit - T * preds$se.fit
upr <- preds$fit + T * preds$se.fit
To create a proper plot of the confidence interval i merge all the necessary info into a single data.frame, while ordering the input, to ensure proper line order.
ord <- order(mtcars$hp)
plotData <- data.frame(lwr = lwr[ord],
upr = upr[ord],
fit = preds$fit[ord],
hp = mtcars$hp[ord],
mpg = mtcars$mpg[ord])
Last but not least we simply need to create the plot, and compare it to the one produced by ggplot2
p1 <- ggplot(plotData, aes(x = hp, ymax = upr, ymin = lwr)) +
#Data points
geom_point(aes(y = mpg)) +
#Line from prediction
geom_line(aes(y = fit)) +
#Points from prediction
geom_point(aes(y = fit)) +
#Confidence interval
geom_ribbon(alpha = 0.3, col = "thistle1") +
labs(title = "manual")
p2 <- ggplot(mtcars, aes(x = hp, y = mpg)) +
geom_point() +
geom_smooth() +
labs(title = "ggplot2")
#Merge plots
library(gridExtra)
grid.arrange(p1, p2, ncol = 1)
Now for the output:
Except for some smoothing done by ggplot, and the added points for the fitted values this is easily seen to be identical.
I hope this clears out how the points confidence interval is calculated.