当样本中的prob参数小于1或大于1时会发生什么?

15
我们知道sample函数中的prob参数用于指定权重的概率。例如,
table(sample(1:4, 1e6, replace = TRUE, prob = c(0.2, 0.4, 0.3, 0.1)))/1e6

#  1   2   3   4 
#0.2 0.4 0.3 0.1 


table(sample(1:4, 1e6, replace = TRUE, prob = c(0.2, 0.4, 0.3, 0.1)))/1e6

#    1     2     3     4 
#0.200 0.400 0.299 0.100 
在这个例子中,概率的总和恰好为1(0.2 + 0.4 + 0.3 + 0.1),因此它给出了期望的比率,但如果概率不等于1呢?它会给出什么输出?我以为它会产生错误,但实际上会给出某个值。
当概率总和大于1时。
table(sample(1:4, 1e6, replace = TRUE, prob = c(0.2, 0.5, 0.5, 0.1)))/1e6

#     1      2      3      4 
#0.1544 0.3839 0.3848 0.0768 

table(sample(1:4, 1e6, replace = TRUE, prob = c(0.2, 0.5, 0.5, 0.1)))/1e6

#     1      2      3      4 
#0.1544 0.3842 0.3848 0.0767 

当概率总和小于1时

table(sample(1:4, 1e6, replace = TRUE, prob = c(0.1, 0.1, 0.5, 0.1)))/1e6

#    1     2     3     4 
#0.124 0.125 0.625 0.125 

table(sample(1:4, 1e6, replace = TRUE, prob = c(0.1, 0.1, 0.5, 0.1)))/1e6

#    1     2     3     4 
#0.125 0.125 0.625 0.125 

正如我们所看到的,运行多次会得到不等于 prob 的输出,但结果也不是随机的。在这种情况下,数字是如何分布的?这在哪里有记录?

我尝试在互联网上搜索,但没有找到相关信息。我查看了在?sample文档中的内容。

可选的 prob 参数可以用于给定一个权重向量,以获取样本向量中的元素。它们不需要总和为1,但应为非负数且不能都为零。如果替换为true,则在有超过200个相当可信的值时使用 Walker's alias 方法(Ripley,1987):这会给出与 R < 2.2.0 不兼容的结果。

因此,它说prob参数不需要总和为1,但是当它不总和为1时期望什么呢?我不确定是否错过了文档的任何部分。有人有什么想法吗?


5
它们被标准化为总和为一。 - user20650
是的,看输出结果,我也这么认为,但在文档中找不到相关信息。 - Ronak Shah
也许在文档中使用“概率权重”而不仅仅是概率会更好。似乎使用权重向量而不是概率更相关。 - user20650
https://www.researchgate.net/post/Hi_there_Is_there_the_value_of_probability_more_than_1 - user10072460
2个回答

18

好问题。文档对此不太清楚,但这个问题可以通过查看源代码来回答。

如果您查看R代码,sample总是调用另一个R函数sample.int 如果将单个数字x传递给sample,它将使用sample.int创建一个小于或等于该数字的整数向量,而如果x是一个向量,则它使用sample.int生成一个小于或等于length(x)的整数样本,然后使用该样本对x进行子集选择。

现在,如果您检查函数sample.int,它看起来像这样:

function (n, size = n, replace = FALSE, prob = NULL, useHash = (!replace && 
    is.null(prob) && size <= n/2 && n > 1e+07)) 
{
    if (useHash) 
        .Internal(sample2(n, size))
    else .Internal(sample(n, size, replace, prob))
}
.Internal的意思是通过调用用C语言编写的已编译代码进行任何采样:在本例中,它是函数do_sample,定义在src/main/random.c中。
如果您查看此C代码,do_sample会检查是否传递了prob向量。如果没有,则假定权重相等进行采样。如果存在prob,则该函数确保它是数字且不为NA。如果prob通过这些检查,则会生成指向双精度数组的底层指针,并将其传递给random.c中的另一个名为FixUpProbs的函数,在这里定义。
该函数检查prob的每个成员,并在任何prob元素不是正有限双精度数时抛出错误。然后通过将每个数除以所有数的总和来归一化这些数字。因此,在代码中根本没有偏好prob总和为1。也就是说,即使您的输入中prob总和为1,该函数仍将计算总和并将每个数字除以它。
因此,该参数命名不当。应该称为“权重”,正如这里其他人所指出的那样。公文只说prob应该是一个权重向量,而不是绝对概率。
因此,根据我对代码的理解,prob参数的行为应该是:
  1. prob可以完全缺失,此时采样默认为等权重。
  2. 如果prob中的任何数字小于零、无穷大或NA,则函数将抛出异常。
  3. 如果prob中的任何值为非数字,则应该抛出错误,因为它们将被解释为SEXP中的NA
  4. prob必须与x具有相同的长度,否则C代码将会抛出异常。
  5. 如果您已经指定了replace=T,则可以将零概率作为prob的一个或多个元素传递,只要您至少有一个非零概率即可。
  6. 如果您指定了replace=F,则您请求的样本数必须小于或等于prob中非零元素的数量。实际上,如果您要求使用零概率进行采样,FixUpProbs将会抛出异常。
  7. 有效的prob向量将被归一化为总和为1,并用作采样权重。

由于这种行为的有趣副作用,如果您通过设置probs = c(1, odds)来在2个选择之间进行选择,这将允许您使用赔率而不是概率。


2
感谢您提供了一份非常深入的答案。关于您在结尾总结中特别提到的第5点,“sample(1:4, 1, prob = c(0, 2, 3, 4))”似乎与“table(replicate(1e6, sample(1:4, 1, prob = c(0, 2, 3, 4))))”在“replace = FALSE”的情况下同样有效。正如文档中所述,“它们不需要加起来等于一,但它们应该是非负的且不全为零”。因此,在“replace = FALSE”的情况下,将一个(或多个但不是全部)值的概率设置为0是否可以接受? - Ronak Shah
2
好观点@RonakShah。实际上,只有在被强制以零的概率进行抽样时,它才会抛出异常。因此,您可以使用sample(1:4, 2, prob = c(0, 0, 2, 3), replace = F),但如果指定n = 3,则一旦样本中存在3和4,它将尝试以0的概率抽取1或2并抛出异常。目前无法测试... - Allan Cameron
2
@RonakShah 我现在已经测试过了,这确实是行为。回答已更新。 - Allan Cameron

7

如前所述,权重已归一化以使总和为1,如下所示:

> x/sum(x)
[1] 0.15384615 0.38461538 0.38461538 0.07692308

这与您模拟的表格数据相匹配:
#     1      2      3      4 
#0.1544 0.3839 0.3848 0.0768 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接