对于交互式模型,手动编码的泊松对数似然函数从glm返回不同的结果

时间:2017-05-21 16:56:36

标签: r regression glm poisson

我编写了自己的Poisson似然函数,但对于具有特定数据交互的模型,它返回的值与glm明显不同。请注意,该函数与我尝试过的所有其他数据以及没有此数据交互的模型的glm结果完全相同。

fun mixAnimalsA(a1: Animal, a2: Animal) =
        when (setOf(a1, a2)) {
            setOf(Animal.OWL, Animal.Leopard) -> Beast.OWLPARD
            setOf(Animal.ELEPHANT, Animal.BUTTERFLY) -> Beast.BUTTERPHANT
            else -> throw Exception("Not possible combination")
        }

这是特定于数据的吗?它是固有的吗? 优化过程,最终会与glm发生更大的分歧,我对这些数据感到不幸?它是使用method =“BFGS”进行优化的函数吗?

2 个答案:

答案 0 :(得分:1)

通过重新调整右侧变量,结果会有很大改善。

> library(data.table)
> setDT(tmp)
> tmp[, x1 := scale(x1)][, x2 := scale(x2)]
> 
> 
> withmyfun = with(tmp, llpoi(cbind(x1, x2, x1 * x2), y))
> withmyfun
[,1]      [,2]
[1,]  0.57076392 0.1124637
[2,] -0.19620040 0.1278070
[3,] -0.01509032 0.1169019
[4,]  0.05636459 0.1380611
> 
> withglm = glm(y ~ x1 + x2 + x1 * x2, family = "poisson", data = tmp)
> summary(withglm)$coef[, 1:2]
Estimate Std. Error
(Intercept)  0.57075132  0.1124641
x1          -0.19618199  0.1278061
x2          -0.01507467  0.1169034
x1:x2        0.05636934  0.1380621
> 

所以,我的建议是,在llpoi内,有一个过程来规范化变量,然后再将optim用于数据,并在函数返回值之前重新调整估计值。您的示例数据范围太大,导致系数估计非常小。由于相对平坦的可能性表面,由于无关紧要的变量,这个问题变得更糟。

注意:

除了拦截之外,您可以获得非常接近的输出。标准化的意思是这样的。

  llpoi = function(X, y){
  # Ensures X is a matrix
  if(class(X) != "matrix") X = as.matrix(X)
  # Ensures there's a constant
  if(sum(X[, 1]) != nrow(X)) X = cbind(1, X)  
  # A useful scalar that I'll need below
  avgs <- c(0, apply(X[, 2:ncol(X)], 2, mean))
  sds <- c(1, apply(X[, 2:ncol(X)], 2, sd))
  X<- t((t(X) - avgs)/sds)

  k = ncol(X)
  ## Function to be maximized
  FUN = function(par, X, y){
    # beta hat -- the parameter we're trying to estimate
    betahat = par[1:k]
    # mu hat -- the systematic component
    muhat = X %*% betahat
    # Log likelihood function
    sum(muhat * y - exp(muhat))
  }
  # Optimizing

  opt = optim(rep(0, k), fn = FUN, y = y, X = X, control = list(fnscale = -1), method = "BFGS", hessian = T)
  # Results, including getting the SEs from the hessian
  cbind(opt$par, sqrt(diag(solve(-1 * opt$hessian))))/sds
}

答案 1 :(得分:-1)

经过大量研究,我了解到两个结果不同,因为glm.fit,glm背后的主力通过Newton-Raphson方法优化了函数,而我在llpoi函数中使用了BFGS。 BFGS更快,但不太精确。在大多数情况下,这两个结果非常相似,但是当表面积过大或者有太多的最大值时可能会有更大的差异,正如amatsuo_net正确指出的那样,因为BFGS使用的攀爬算法会卡住。