当向量长度为一时,R中的sample()函数是不可预测的。

3

我正在尝试调试一个简短的程序,在某些条件下从向量元素中抽取样本时,最后得到了令人不安的结果。当向量中剩余的元素减少到单个值时会出现此问题。

在我所指的特定情况下,向量被称为remaining,包含一个单独的元素,即数字2。我期望从该向量中抽取大小为1的任何样本都会顽固地返回2,因为它是向量中唯一的元素,但事实并非如此:

Browse[2]> is.vector(remaining)
[1] TRUE
Browse[2]> sample(remaining,1)
[1] 2
Browse[2]> sample(remaining,1)
[1] 2
Browse[2]> sample(remaining,1)
[1] 1
Browse[2]> sample(x=remaining, size=1)
[1] 1
Browse[2]> sample(x=remaining, size=1)
[1] 2
Browse[2]> sample(x=remaining, size=1)
[1] 1
Browse[2]> sample(x=remaining, size=1)
[1] 1
Browse[2]> sample(x=remaining, size=1)
[1] 1

正如您所看到的,有时返回值是1,有时是2

我对sample()函数的理解有什么误解吗?


Browse[2]> all(remaining==2) [1] TRUE - Antoni Parellada
1个回答

4

来自help("sample")

如果x的长度为1,是数字(指is.numeric)并且x>=1,则通过样本抽取将从1:x进行。

因此,当您有remaining = 2时,sample(remaining)相当于sample(x = 1:2)

更新

从评论中可以清楚地看出,您也正在寻找一种解决此行为的方法。这里是三种提到的替代方案的基准比较:

library(microbenchmark)

# if remaining is of length one
remaining <- 2

microbenchmark(a = {if ( length(remaining) > 1 ) { sample(remaining) } else { remaining }},
               b = ifelse(length(remaining) > 1, sample(remaining), remaining),
               c = remaining[sample(length(remaining))])

Unit: nanoseconds
 expr  min   lq    mean median     uq   max neval cld
    a  349  489  625.12  628.0  663.5  3283   100 a  
    b 1536 1886 2240.58 2025.0 2165.5 13898   100  b 
    c 4051 4400 5193.41 4679.5 5064.0 38413   100   c

# If remaining is not of length one
remaining <- 1:10
microbenchmark(a = {if ( length(remaining) > 1 ) { sample(remaining) } else { remaining }},
               b = ifelse(length(remaining) > 1, sample(remaining), remaining),
               c = remaining[sample(length(remaining))])

Unit: microseconds
 expr    min      lq     mean median      uq    max neval cld
    a  5.238  5.7970  6.82703  6.251  6.9145 51.264   100  a 
    b 11.663 12.2920 13.14831 12.851 13.3745 34.851   100   b
    c  5.238  5.9715  6.57140  6.426  6.8450 14.667   100  a 

看起来来自joran的建议可能是您情况下最快的,如果sample()remaining长度>1时被调用得更频繁,则if() {} else {}的方法会更快。


@Toni 这种行为是因为对长度为1的向量进行抽样是没有意义的;只有一个可能的答案,即向量本身,甚至没有从向量中派生出的某些值。 - duckmayr
@aocall 这意味着代码中需要增加一行或两行。应该有一种方法来解决sample()函数这种混乱的行为... - Antoni Parellada
remaining <- c( 2, 2 ) - vaettchen
@Toni 这是一个非常古老的“陷阱”,起源于 R(或 S,可能)试图为交互式工作提供帮助,允许将常见情况 sample(1:n) 的规范缩短为 sample(n)。大多数人事后都认为这是不明智的,但行为现在已经如此古老,并且很多东西都依赖于该行为,所以我们被困在其中。 - joran
1
@Toni 或许可以使用以下代码:if ( length(remaining) > 1 ) { sample(remaining) } else { remaining },因为你不需要 ifelse() 的向量化和减速。 - duckmayr
显示剩余6条评论

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