我对R中的样本函数有一个简单的问题。我从0和1中随机抽样并将它们加在一起,从长度为5的输入向量求和,它指定要运行的试验次数并将种子设置为生成可重现的随机数。种子按预期工作,但我根据我在prob语句中的内容得到不同的随机数矩阵。在这种情况下,我假设prob = NULL应该与prob = c(0.5,0.5)相同。为什么不呢?
vn<-c(12, 44, 9, 17, 28)
> do.call(cbind, lapply(c(1:10),function(X) {set.seed(X); sapply(vn, function(Y) sum(sample(x=c(0,1),size=Y,replace=T)), simplify=TRUE)}))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 6 7 7 6 6 9 3 6 2 5
[2,] 22 21 20 29 22 24 24 19 25 19
[3,] 4 8 3 5 4 4 4 6 4 2
[4,] 8 4 12 9 11 7 9 10 8 8
[5,] 13 9 11 14 12 14 10 13 11 12
> do.call(cbind, lapply(c(1:10),function(X) {set.seed(X); sapply(vn, function(Y) sum(sample(x=c(0,1),size=Y,replace=T, prob=c(0.5,0.5))), simplify=TRUE)}))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 6 5 5 6 6 3 9 6 10 7
[2,] 22 23 24 15 22 20 20 25 19 25
[3,] 5 1 6 4 5 5 5 3 5 7
[4,] 9 13 5 8 6 10 8 7 9 9
[5,] 15 19 17 14 16 14 18 15 17 16
更新:
我使用输入向量
将采样扩展到100vn<-seq(0,100,5)
并将没有概率(test1)和prob = c(0.5,0.5)的输出矩阵的rowMeans与预期平均值进行比较。有趣的是,test1和test2通过反转符号完全相同。这是为什么?谢谢!
> rowMeans(test1)-seq(0,100,5)/2
[1] 0.00 -0.07 -0.01 -0.35 -0.07 0.19 -0.07 0.24 0.21 0.46 0.20 0.50 -0.37 -0.35 0.00 0.64 -0.59 0.63 -1.19 0.44 -0.38
> rowMeans(test2)-seq(0,100,5)/2
[1] 0.00 0.07 0.01 0.35 0.07 -0.19 0.07 -0.24 -0.21 -0.46 -0.20 -0.50 0.37 0.35 0.00 -0.64 0.59 -0.63 1.19 -0.44 0.38
答案 0 :(得分:4)
我将评论更新为答案。 sample
使用不同的c例程进行统一采样和加权采样。虽然你使用的是相同的权重,但无论如何R都会调用加权采样。
要看到这一点,请考虑
> set.seed(1)
> sample.int(100)
[1] 27 37 57 89 20 86 97 62 58 6 19 16 61 34 67 43 88 83
[19] 32 63 75 17 51 10 21 29 1 28 81 25 87 42 70 13 55 44
[37] 78 7 45 26 50 39 46 82 30 65 2 84 59 36 24 85 22 12
[55] 4 5 14 23 73 79 99 47 18 95 60 77 41 53 3 69 11 71
[73] 35 31 40 49 76 9 38 64 80 66 8 91 33 92 100 54 98 94
[91] 52 74 68 72 93 15 56 48 90 96
> set.seed(1)
> sample.int(100, prob = rep(1/100, 100))
[1] 28 39 60 93 21 91 96 67 63 7 22 18 71 41 79 51 74 1
[19] 38 78 94 20 64 12 29 40 2 42 87 35 50 61 52 17 84 69
[37] 81 10 73 44 85 65 80 54 49 82 4 46 75 68 43 90 36 23
[55] 8 11 30 55 66 34 97 26 47 31 70 24 53 86 6 95 32 89
[73] 27 33 56 98 88 25 77 100 37 62 19 15 76 13 59 5 14 9
[91] 45 3 83 99 72 58 48 57 92 16
请注意两个不同的采样序列。
答案 1 :(得分:3)
正如Randy所建议的那样,sample.int
使用了不同的例程,具体取决于prop
是否为NULL。
在您的情况下,它会返回反向结果:
> set.seed(1); sample(c(0,1), size=20, replace=TRUE)
[1] 0 0 1 1 0 1 1 1 1 0 0 0 1 0 1 0 1 1 0 1
> set.seed(1); sample(c(0,1), size=20, replace=TRUE, prob=c(.5,.5))
[1] 1 1 0 0 1 0 0 0 0 1 1 1 0 1 0 1 0 0 1 0
发生了什么?
对于前者,我们点击src/main/random.c:546
行:
for (int i = 0; i < k; i++) iy[i] = (int)(dn * unif_rand() + 1);
这个很简单。 unif_rand()
返回介于0和1之间的值(并且永远不会返回1),dn
为2(x
中的元素数量),因此iy[i]
设置为{{ 1}}或1
,具体取决于2
是否分别返回值unif_rand()
或< .5
;这是从>= .5
中选择的值。
后者有点复杂。由于指定了x
,prob
会在do_sample
调用函数ProbSampleReplace
。在这里,概率按照降序排序,函数src/main/random.c:309
位于revsort
。这对概率使用堆排序,并且使用具有相等概率的双元素向量,它会反转顺序。
src/main/sort.c:248
再次调用ProbSampleReplace
,但这一次将其映射到翻转向量顺序后计算的累积概率,因此如果unif_rand()
返回值unif_rand()
,返回第二个值(在您的示例中为< 0.5
)。这是将1
映射到unif_rand()
:
x
因此,在两个元素的概率相等的情况下,将概率明确设置为/* compute the sample */
for (i = 0; i < nans; i++) {
rU = unif_rand();
for (j = 0; j < nm1; j++) {
if (rU <= p[j])
break;
}
ans[i] = perm[j];
}
将返回相同调用的反转而不设置概率。有两个以上的元素,它不会总是反转它们,但它不会返回相同的顺序。
这也解释了为什么费尔南多的建议有效。这些值足够接近.5,以便不更改此示例的结果,并且堆排序以原始顺序返回值。
此表达式返回与第一行代码相同的矩阵:
c(0.5, 0.5)
此处,do.call(cbind, lapply(c(1:10),function(X) {set.seed(X); sapply(vn, function(Y) sum(sample(x=c(1,0),size=Y,replace=T, prob=c(0.5,0.5))), simplify=TRUE)}))
中条目的顺序已被反转,以考虑两个元素的相等值排序(交换条目)。
当然这都是学术性的。在实践中,置换等概率条目的顺序并不重要。
上面的源文件和行号参考x
。