logLik 为正态线性模型返回的对数似然与手动计算之间存在差异 "standard"

Discrepancy between log-likelihood returned by logLik for normal linear models and "standard" manual calculation

lm 方法为 logLik 函数返回的对数似然似乎与手动计算的不匹配。

为了演示,下面我将一个只有截距的标准线性模型拟合到一个具有三个点的简单数据集。然后,我使用 logLik 提取对数似然,并通过对在 mle 评估的 pdf 的日志求和来手动计算它。

test_df <- data.frame(y = c(0, 2, 4))
mod_lm <- lm(y ~ 1, data = test_df)
ll_logLik <- logLik(mod_lm)
ll_manual <- sum(log(purrr::map_dbl(test_df$y, function(x) dnorm(x, 
                                                   mean = mod_lm$coefficients[1], 
                                                   sd = summary(mod_lm)$sigma))))
c("logLik" = ll_logLik, "manual" = ll_manual)

从上面可以看出,泛型logLik returns -5.836 而手动计算returns -5.728.

深入logLik(stats:::logLik.lm)调用的方法,计算log-likelihood的关键行可以写成

n <- nrow(test_df); resid_vec <- mod_lm$residuals
-n/2  * (log(2 * pi) + 1 - log(n) + log(sum(resid_vec^2)))

和以前一样给出 -5.728。

但是,根据我期望的以下对数似然公式,

sigma <- summary(mod_lm)$sigma
-n/2 * log(2 * pi) - n * log(sigma) - 1/2/sigma^2 * sum(resid_vec^2)

我之前手动计算得到 -5.826。

如果你将一个模型拟合到更多的数据点,比如1e4,那么人工计算返回的结果,我的公式和logLik直到7个重要的地方都是一样的(之后不确定)。例如:

set.seed(4)
test_df <- data.frame(y = rnorm(1e4))
mod_lm <- lm(y ~ 1, data = test_df)
ll_logLik <- logLik(mod_lm)
ll_manual <- sum(log(purrr::map_dbl(test_df$y, function(x) dnorm(x, 
                                                   mean = mod_lm$coefficients[1], 
                                                   sd = summary(mod_lm)$sigma))))
c("logLik" = ll_logLik, "manual" = ll_manual)

两者都产生 -14155.41。

怎么回事?

logLik 在参数的最大似然估计值处评估对数似然。系数的最大似然估计与最小二乘估计相同,但方差的最大似然估计的分母是 n,而 summary(mod_lm)$sigma 是方差的平方根方差的无偏估计,其分母是自由度,这里 n-1。所以如果你这样做,你会得到相同的结果:

sd = sqrt(2/3)* summary(mod_lm)$sigma