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

R 对于交互模型,手动编码的泊松对数似然函数返回与glm不同的结果,r,regression,glm,poisson,R,Regression,Glm,Poisson,我已经编写了自己的泊松似然函数,但它返回的值与具有特定数据交互作用的模型的glm有很大不同。请注意,该函数从我尝试过的所有其他数据中,以及在没有与该数据交互的情况下,为模型吐出与glm完全相同的结果 > # Log likelihood function > llpoi = function(X, y){ + # Ensures X is a matrix + if(class(X) != "matrix") X = as.matrix(X) + # Ensures th

我已经编写了自己的泊松似然函数,但它返回的值与具有特定数据交互作用的模型的glm有很大不同。请注意,该函数从我尝试过的所有其他数据中,以及在没有与该数据交互的情况下,为模型吐出与glm完全相同的结果

> # Log likelihood function
> 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
+   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))))
+ }
> 
> # Defining inputs 
> y = c(2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 3, 1, 1, 3, 2, 2, 2, 3, 1, 2, 4, 3, 3, 3, 1, 3, 0, 2, 1, 2, 4, 1, 2, 0, 2, 1, 2, 1, 4, 1, 2, 0)
> x1 = c(8, 1, 0, 3, 3, 3, 5, 4, 0.4, 1.5, 2, 1, 1, 7, 2, 3, 0, 2, 1.5, 5, 1, 4, 5.5, 6, 3, 3, 2, 0.5, 5, 10, 3, 22, 20, 3, 20, 10, 15, 25, 15, 6, 3.5, 5, 18, 2, 15.0, 16, 24)
> x2 = c(12, 12, 12, 16, 12, 12, 12, 12, 12, 12, 12, 12, 9, 9, 12, 9, 12, 12, 9, 16, 9, 6, 12, 9, 9, 12, 12, 12, 12, 14, 14, 14, 9, 12, 9, 12, 3, 12, 9, 6, 12, 12, 12, 12, 12, 12, 9)
> 
> # Results
> withmyfun = llpoi(cbind(x1, x2, x1 * x2), y)
> round(withmyfun, 2)
      [,1] [,2]
[1,]  0.96 0.90
[2,] -0.05 0.09
[3,] -0.02 0.08
[4,]  0.00 0.01
> withglm = glm(y ~ x1 + x2 + x1 * x2, family = "poisson")
> round(summary(withglm)$coef[, 1:2], 2)
            Estimate Std. Error
(Intercept)     1.08       0.90
x1             -0.07       0.09
x2             -0.03       0.08
x1:x2           0.00       0.01
这是特定于数据的吗?这是与生俱来的吗
优化过程,最终会与glm产生更大的分歧,而我只是不幸地得到了这些数据?这是使用method=“BFGS”进行optim的函数吗?

通过重新缩放右侧变量,结果会有很大改善

> 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
}
llpoi=函数(X,y){
#确保X是一个矩阵
如果(类(X)!=“矩阵”)X=as.matrix(X)
#确保有一个常数
if(sum(X[,1])!=nrow(X))X=cbind(1,X)
#下面我需要一个有用的标量

avgs经过大量研究,我了解到这两个结果不同,因为glm背后的主力glm.fit通过牛顿-拉斐逊方法优化函数,而我在llpoi函数中使用了BFGS。BFGS更快,但精度更低。在大多数情况下,这两个结果非常相似,但在表面积为正如amatsuo_net正确指出的那样,oo平坦或有太多的最大值,因为BFGS使用的爬升算法将被卡住。

这个问题可能会从交叉验证堆栈中得到更好的答案,因为这个问题更多的是关于统计上下文而不是R代码。你是对的。我可以移动这个问题吗,或者只有主持人可以这样做?我会复制并粘贴到那里。我有一些编辑能力,但没有那么多。对不起!我不太关心模型拟合(事实上我知道这是一个非常糟糕的模型),而更关心glm的可复制性。我想了解为什么结果如此不同,以及如何最小化差异,而不管数据如何。“如何最小化差异”是我要说的。你需要规范化(我指的是标准化)如果你想得到类似于
glm
的结果,那么在函数中使用
optim
之前的数据。我在代码中展示的是,通过标准化函数外的变量,你可以得到非常相似的结果,因为对于这种格式良好的数据,
llpoi
表现得与
glm
一样好。为什么你需要标准化数据可以在其他地方找到(例如),但请注意,除非用户在调用glm之前也对数据进行标准化,包括llpoi中的标准化不会解决我的问题;glm和llpoi的结果不会几乎相同,这正是我所寻求的。