罕见事件逻辑回归偏差:如何用最小示例模拟被低估的 p?

机器算法验证 r 物流 模拟 偏见 罕见事件
2022-01-28 12:55:14

CrossValidated 有几个关于何时以及如何应用King 和 Zeng (2001)的罕见事件偏差校正的问题。我正在寻找不同的东西:基于最小模拟的证明存在偏差。

特别是国王和曾国

“......在罕见事件数据中,概率偏差在数千个样本量下可能具有实质性意义,并且处于可预测的方向:估计的事件概率太小。”

这是我在 R 中模拟这种偏差的尝试:

# FUNCTIONS
do.one.sim = function(p){
    N = length(p)
    # Draw fake data based on probabilities p  
    y = rbinom(N, 1, p)  
    # Extract the fitted probability.
    #    If p is constant, glm does y ~ 1, the intercept-only model.
    #    If p is not constant, assume its smallest value is p[1]:
    glm(y ~ p, family = 'binomial')$fitted[1]
}
mean.of.K.estimates = function(p, K){
    mean(replicate(K, do.one.sim(p) ))
}

# MONTE CARLO
N = 100
p = rep(0.01, N)
reps = 100
# The following line may take about 30 seconds
sim = replicate(reps, mean.of.K.estimates(p, K=100))
# Z-score:
abs(p[1]-mean(sim))/(sd(sim)/sqrt(reps))
# Distribution of average probability estimates:
hist(sim)

当我运行这个时,我倾向于得到非常小的 z 分数,并且估计的直方图非常接近于以真值 p = 0.01 为中心。

我错过了什么?是不是我的模拟不够大,无法显示真实的(显然非常小的)偏差?偏差是否需要包含某种协变量(超过截距)?

更新 1: King 和 Zeng在他们论文的等式 12 中注意到分母中的 ,我大幅减少并重新运行了模拟,但估计的事件概率仍然没有明显的偏差。(我仅将此用作灵感。请注意,我上面的问题是关于估计的事件概率,而不是。)β0NN5β^0

更新 2:根据评论中的建议,我在回归中加入了一个自变量,得到了相同的结果:

p.small = 0.01
p.large = 0.2
p = c(rep(p.small, round(N/2) ), rep(p.large, N- round(N/2) ) )
sim = replicate(reps, mean.of.K.estimates(p, K=100))

解释:我用p自己作为自变量,这里p是一个向量,重复一个小值(0.01)和一个大值(0.2)。最后,sim只存储对应于的估计概率,并且没有偏差的迹象。p=0.01

更新 3(2016 年 5 月 5 日): 这并没有明显改变结果,但我的新内部模拟函数是

do.one.sim = function(p){
    N = length(p)
    # Draw fake data based on probabilities p  
    y = rbinom(N, 1, p)
    if(sum(y) == 0){ # then the glm MLE = minus infinity to get p = 0
        return(0)
    }else{
        # Extract the fitted probability.
        #    If p is constant, glm does y ~ 1, the intercept only model.
        #    If p is not constant, assume its smallest value is p[1]:
        return(glm(y ~ p, family = 'binomial')$fitted[1])
    }
}

说明:当 y 为零时的 MLE 不存在(感谢此处的评论提醒)。R 未能发出警告,因为它的“正收敛容差”实际上得到了满足。更自由地说,MLE 存在并且是负无穷大,对应于因此我的功能更新。我能想到的唯一其他连贯的事情是丢弃那些 y 相同为零的模拟运行,但这显然会导致结果与最初声称的“估计的事件概率太小”更加相反。p=0

3个回答

这是一个有趣的问题——我已经做了一些模拟,我在下面发布了这些模拟,希望这能激发进一步的讨论。

首先,一些一般性评论:

  • 你引用的论文是关于罕见事件偏差的。我之前不清楚(也关于上面的评论)是如果你有 10/10000 而不是 10/30 观察的情况有什么特别之处。但是,经过一些模拟,我同意存在。

  • 我想到的一个问题(我经常遇到这个问题,最近在生态学和进化的方法中有一篇论文,但我找不到参考资料)是你可以在小数据中得到 GLM 的退化案例在这种情况下,MLE 与事实相距甚远,甚至在 - / + 无穷大(我想是由于非线性链接)。我不清楚在偏差估计中应该如何处理这些情况,但从我的模拟来看,我会说它们似乎是罕见事件偏差的关键。我的直觉是删除它们,但是还不清楚它们必须被删除多远。对于偏差校正,也许要记住一些事情。

  • 此外,这些退化的情况似乎容易导致数值问题(因此我增加了 glm 函数中的 maxit,但人们也可以考虑增加 epsilon 以确保实际报告真正的 MLE)。

无论如何,这里有一些代码计算逻辑回归中截距、斜率和预测的估计值和真值之间的差异,首先是针对低样本量/中等发生率的情况:

set.seed(123)
replicates = 1000
N= 40
slope = 2 # slope (linear scale)
intercept = - 1 # intercept (linear scale)

bias <- matrix(NA, nrow = replicates, ncol = 3)
incidencePredBias <- rep(NA, replicates)

for (i in 1:replicates){
  pred = runif(N,min=-1,max=1) 
  linearResponse = intercept + slope*pred
  data = rbinom(N, 1, plogis(linearResponse))  
  fit <- glm(data ~ pred, family = 'binomial', control = list(maxit = 300))
  bias[i,1:2] = fit$coefficients - c(intercept, slope)
  bias[i,3] = mean(predict(fit,type = "response")) - mean(plogis(linearResponse))
}

par(mfrow = c(1,3))
text = c("Bias intercept", "Bias slope", "Bias prediction")

for (i in 1:3){
  hist(bias[,i], breaks = 100, main = text[i])
  abline(v=mean(bias[,i]), col = "red", lwd = 3)  
}

apply(bias, 2, mean)
apply(bias, 2, sd) / sqrt(replicates)

截距、斜率和预测的偏差和标准误差为

-0.120429315  0.296453122 -0.001619793
 0.016105833  0.032835468  0.002040664

我会得出结论,有很好的证据表明截距有轻微的负偏差,斜率有轻微的正偏差,尽管看一下绘制的结果表明,与估计值的方差相比,偏差很小。

在此处输入图像描述

如果我将参数设置为罕见情况

N= 4000
slope = 2 # slope (linear scale)
intercept = - 10 # intercept (linear scale)

我对截距有更大的偏差,但预测仍然没有

   -1.716144e+01  4.271145e-01 -3.793141e-06
    5.039331e-01  4.806615e-01  4.356062e-06

在估计值的直方图中,我们看到了退化参数估计的现象(如果我们应该这样称呼的话)

在此处输入图像描述

让我们删除所有截距估计值 <20 的行

apply(bias[bias[,1] > -20,], 2, mean)
apply(bias[bias[,1] > -20,], 2, sd) / sqrt(length(bias[,1] > -10))

偏差减少了,图中的情况变得更加清晰——参数估计显然不是正态分布的。我想知道这意味着报告的 CI 的有效性。

-0.6694874106  1.9740437782  0.0002079945
1.329322e-01 1.619451e-01 3.242677e-06

在此处输入图像描述

我会得出结论,截距上的罕见事件偏差是由罕见事件本身驱动的,即那些罕见的、极小的估计。不确定我们是否要删除它们,不确定截止日期是什么。

不过需要注意的重要一点是,无论哪种方式,响应规模的预测似乎都没有偏差——链接函数只是吸收了这些极小的值。

论文中的图 7 似乎最直接地解决了预测中的偏差问题。我不完全理解这个数字(具体来说,“估计的事件概率太小”的解释似乎过于简单化了)但我设法根据他们在第 6.1 节中对模拟的简洁描述重现了类似的东西:

n_grid = 40
x_grid = seq(0, 7, length.out = n_grid)
beta0 = -6
beta1 = 1

inverse_logit = function(x) 1/(1 + exp(-x))

do.one.sim = function(){
    N = 5000
    x = rnorm(N)
    p = inverse_logit(beta0 + beta1*x)
    # Draw fake data based on probabilities p
    y = rbinom(N, 1, p)
    if(sum(y) == 0){ # then the glm MLE = minus infinity to get p = 0
        return(rep(0, n_grid))
    }else{
        # Extract the error
        mod = glm(y ~ x, family = 'binomial')
        truth = inverse_logit(beta0 + beta1*x_grid)
        pred = predict(mod, newdata = data.frame(x = x_grid),
            type = 'response')
        return(pred - truth)
    }
}
mean.of.K.estimates = function(K){
    rowMeans(replicate(K, do.one.sim()))
}

set.seed(1)
bias = replicate(10, mean.of.K.estimates(100))
maxes = as.numeric(apply(bias, 1, max))
mins = as.numeric(apply(bias, 1, min))

par(mfrow = c(3, 1), mar = c(4,4,2,2))
plot(x_grid, rowMeans(bias), type = 'l',
    ylim = c(min(bias), max(bias)),
    xlab = 'x', ylab = 'bias')
lines(x_grid, maxes, lty = 2)
lines(x_grid, mins, lty = 2)
plot(x_grid, dnorm(x_grid), type = 'l',
    xlab = 'x', ylab = 'standard normal density')
plot(x_grid, inverse_logit(beta0 + beta1*x_grid),
    xlab = 'x', ylab = 'true simulation P(Y = 1)',
    type = 'l')

第一个图是我对他们的图 7 的复制,添加了代表 10 次试验的全部结果的虚线曲线。

根据论文,x这是从标准正态提取的回归中的预测变量。因此,如第二个图所示,观察的相对频率x > 3(在第一个图中出现最明显的偏差)越来越小。

第三幅图显示了生成过程中的“真实”模拟概率作为 的函数x似乎最大的偏差发生在x罕见或不存在的地方。

总而言之,这些表明 OP 通过将“罕见事件”(即x > 3)与“P(Y = 1)非常小的事件”混淆起来,完全误解了论文的中心主张。据推测,这篇论文涉及的是前者而不是后者。

在此处输入图像描述

罕见事件偏差仅在存在回归变量时发生。它不会出现在像这里模拟的那样只截取的模型中。有关详细信息,请参阅此帖子: http ://statisticalhorizo​​ns.com/linear-vs-logistic#comment-276108