如何找到事件总数的置信区间

机器算法验证 可能性 置信区间
2022-03-11 07:27:23

我有检测器,它将以一定的概率检测事件p如果检测器说发生了事件,那么情况总是如此,因此不会出现误报。运行一段时间后,我检测到k 个事件。我想计算发生的事件总数是多少,检测到或其他,有一定的信心,比如 95%。

例如,假设我检测到 13 个事件。我希望能够根据p计算出 13 到 19 个事件的置信度为 95% 。

这是我到目前为止所尝试的:

如果总共有n 个事件,则检测到k个事件的概率为:

binomial(n, k) * p^k * (1 - p)^(n - k)

k到无穷大的n的总和是:

1/p

这意味着,总共有n 个事件的概率是:

f(n) = binomial(n, k) * p^(k + 1) * (1 - p)^(n - k)

因此,如果我想 95% 确定我应该找到f(k) + f(k+1) + f(k+2) ... + f(k+m)至少为 0.95 的第一个部分总和,答案是[k, k+m]. 这是正确的方法吗?还有一个封闭的答案公式吗?

4个回答

我会选择使用负二项分布,当成功的常数概率为 p 时,它返回在第 k 次成功之前会有 X 次失败的概率。

使用示例

k=17 # number of successes
p=.6 # constant probability of success

失败的平均值和标准差由下式给出

mean.X <- k*(1-p)/p
sd.X <- sqrt(k*(1-p)/p^2) 

故障 X 的分布将大致具有该形状

plot(dnbinom(0:(mean.X + 3 * sd.X),k,p),type='l')

因此,失败的数量将(95% 置信度)大约在

qnbinom(.025,k,p)
[1] 4

qnbinom(.975,k,p)
[1] 21

所以你 inerval 将是 [k+qnbinom(.025,k,p),k+qnbinom(.975,k,p)] (使用示例的数字 [21,38] )

假设您想选择 n, p(n) 的分布,您可以应用贝叶斯定律。

你知道,在 n 实际发生的情况下,k 个事件发生的概率受二项式分布的支配

p(k|n)=(nk)pk(1p)(nk)

假设你观察到 k,你真正想知道的是 n 个事件实际发生的概率。通过贝叶斯奠定:

p(n|k)=p(k|n)p(n)p(k)

通过应用总概率定理,我们可以写出:

p(n|k)=p(k|n)p(n)np(k|n)p(n)

因此,如果没有更多信息,关于的分布,您将无法再进一步。p(n)

但是,如果您想为选择一个分布,其值大于或足够接近零,那么您可以做得更好。例如,假设范围内是均匀的这个案例:p(n)np(n)=0n[0,nmax]

p(n)=1nmax

贝叶斯公式简化为:

p(n|k)=p(k|n)np(k|n)

至于问题的最后一部分,我同意最好的方法是对执行累积求和,以生成累积概率分布函数,并迭代直到达到 0.95 限制。p(n|k)

鉴于这个问题是从 SO 迁移而来的,下面附上了 python 中的玩具示例代码

import numpy.random

p = 0.8
nmax = 200

def factorial(n):
    if n == 0:
        return 1
    return reduce( lambda a,b : a*b, xrange(1,n+1), 1 )

def ncr(n,r):
    return factorial(n) / (factorial(r) * factorial(n-r))

def binomProbability(n, k, p):
    p1 = ncr(n,k)
    p2 = p**k
    p3 = (1-p)**(n-k)
    return p1*p2*p3

def posterior( n, k, p ):
    def p_k_given_n( n, k ):
        return binomProbability(n, k, p)
    def p_n( n ):
        return 1./nmax
    def p_k( k ):
        return sum( [ p_n(nd)*p_k_given_n(nd,k) for nd in range(k,nmax) ] )
    return (p_k_given_n(n,k) * p_n(n)) / p_k(k)


observed_k   = 80
p_n_given_k  = [ posterior( n, observed_k, p ) for n in range(0,nmax) ]
cp_n_given_k = numpy.cumsum(p_n_given_k)
for n in xrange(0,nmax):
    print n, p_n_given_k[n], cp_n_given_k[n]

如果您测量个事件并知道您的检测效率为,您可以自动将您的测量结果校正到“真实”计数kpktrue=k/p

那么你的问题是关于找到的范围,其中 95% 的观测值将落在该范围内。您可以使用Feldman-Cousins 方法来估计此间隔。如果您有权访问ROOT,则有一个类可以为您进行此计算。ktrue

您将使用 Feldman-Cousins 从未校正的事件计算上限和下限 将它们放大到 100% 这样,实际的测量次数决定了您的不确定性,而不是一些未测量的缩放数字。k1/p

{
gSystem->Load("libPhysics");

const double lvl = 0.95;
TFeldmanCousins f(lvl);

const double p = 0.95;
const double k = 13;
const double k_true = k/p;

const double k_bg = 0;

const double upper = f.CalculateUperLimit(k, k_bg) / p;
const double lower = f.GetLowerLimit() / p;

std::cout << "["
  lower <<"..."<<
  k_true <<"..."<<
  upper <<
  "]" << std::endl;
}

我认为您误解了置信区间的目的。置信区间允许您评估参数的真实值所在的位置。构建置信区间为数据构造一个区间是没有意义的。p

进行了估计,您就可以使用二项式 pdf 计算您将观察到不同实现(例如 14、15 等)的概率。p