【问题标题】:Assigning a specific number of values informed by a probability distribution (in R)分配由概率分布通知的特定数量的值(在 R 中)
【发布时间】:2011-08-04 03:50:54
【问题描述】:

您好,提前感谢您的帮助!

我正在尝试生成一个向量,该向量具有根据概率分布分配的特定数量的值。例如,我想要一个长度为 31 的向量,包含 26 个 0 和 5 个 1。 (向量的总和应始终为 5。)但是,向量的位置很重要。为了确定哪些值应该为 1,哪些值应该为零,我有一个概率向量(长度为 31),如下所示:

probs<-c(0.01,0.02,0.01,0.02,0.01,0.01,0.01,0.04,0.01,0.01,0.12,0.01,0.02,0.01,
0.14,0.06,0.01,0.01,0.01,0.01,0.01,0.14,0.01,0.07,0.01,0.01,0.04,0.08,0.01,0.02,0.01)

我可以根据这个分布选择值,并使用 rbinom 得到一个长度为 31 的向量,但我不能准确地选择五个值。

Inv=rbinom(length(probs),1,probs)
Inv
[1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0

有什么想法吗?

再次感谢!

【问题讨论】:

  • "向量的总和应该始终为 1"。你的意思是“......应该永远是五个”?
  • 你是对的!我修好了它。谢谢。

标签: r vector probability


【解决方案1】:

仅使用加权sample.int 来选择位置怎么样?

Inv<-integer(31)
Inv[sample.int(31,5,prob=probs)]<-1
Inv
[1] 0 0 0 1 0 1 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0

【讨论】:

  • +1 太棒了,我在阅读问题和@Chase 的答案时正在考虑使用sample(),但您显示的用法让我无法理解。
  • 这肯定更快,大约 20 分钟,一个 1000 个模拟人生的周期。谢谢!
【解决方案2】:

Chase 提供了一个很好的答案,并提到了 while() 迭代失控的问题。失控的while() 的问题之一是,如果您一次进行一次试验,并且需要多次试验,比如 t,才能找到与 @ 的目标数量相匹配的试验。 987654323@s,您会产生 t 调用 main 函数的开销,在这种情况下为 rbinom()

但是有一条出路,因为rbinom(),就像 R 中的所有这些(伪)随机数生成器一样,是矢量化的,我们可以一次生成 m 个试验并检查那些m 试验以符合 5 1s 的要求。如果没有找到,我们会反复进行 m 次试验,直到找到符合要求的试验。这个想法在下面的函数foo() 中实现。 chunkSize 参数是 m,即一次要绘制的试验次数。我还借此机会允许该函数查找多个保形试验;参数n 控制要返回多少保形试验。

foo <- function(probs, target, n = 1, chunkSize = 100) {
    len <- length(probs)
    out <- matrix(ncol = len, nrow = 0) ## return object
    ## draw chunkSize trials
    trial <- matrix(rbinom(len * chunkSize, 1, probs),
                    ncol = len, byrow = TRUE)
    rs <- rowSums(trial)  ## How manys `1`s
    ok <- which(rs == 5L) ## which meet the `target`
    found <- length(ok)   ## how many meet the target
    if(found > 0)         ## if we found some, add them to out
        out <- rbind(out,
                     trial[ok, , drop = FALSE][seq_len(min(n,found)), , 
                                               drop = FALSE])
    ## if we haven't found enough, repeat the whole thing until we do
    while(found < n) {
        trial <- matrix(rbinom(len * chunkSize, 1, probs),
                            ncol = len, byrow = TRUE)
        rs <- rowSums(trial)
        ok <- which(rs == 5L)
        New <- length(ok)
        if(New > 0) {
            found <- found + New
            out <- rbind(out, trial[ok, , drop = FALSE][seq_len(min(n, New)), , 
                                                        drop = FALSE])
        }
    }
    if(n == 1L)           ## comment this, and
        out <- drop(out)  ## this if you don't want dimension dropping
    out
}

它是这样工作的:

> set.seed(1)
> foo(probs, target = 5)
 [1] 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0
[31] 0
> foo(probs, target = 5, n = 2)
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11]
[1,]    0    0    0    0    0    0    0    0    0     0     0
[2,]    0    0    0    0    0    0    0    0    0     0     1
     [,12] [,13] [,14] [,15] [,16] [,17] [,18] [,19] [,20] [,21]
[1,]     0     0     0     1     1     0     0     0     0     0
[2,]     0     1     0     0     1     0     0     0     0     0
     [,22] [,23] [,24] [,25] [,26] [,27] [,28] [,29] [,30] [,31]
[1,]     1     0     1     0     0     0     1     0     0     0
[2,]     1     0     1     0     0     0     0     0     0     0

请注意,我在n == 1 的情况下删除了空维度。如果您不想要此功能,请将最后一个 if 代码块注释掉。

您需要平衡chunkSize 的大小和一次检查这么多试验的计算负担。如果要求(这里是 5 个1s)不太可能,那么增加chunkSize 以便减少对rbinom() 的调用。如果可能需要,那么如果您只想要一两个,则一次很少有点画试验和大chunkSize,因为您必须评估每个试画。

【讨论】:

  • +1 尽管这种努力值得更好。很好的答案,谢谢。
  • 我会回应 Andrie 的 cmets。这是一个更具可扩展性的解决方案。我正在考虑矢量化,但不知道如何在这里利用它,干得好 +1。
  • 这太棒了,但我认为我需要一段时间才能完成它。 :)
【解决方案3】:

我认为您希望使用给定的一组概率从二项分布中重新采样,直到您达到目标值 5,对吗?如果是这样,那么我认为这可以满足您的要求。 while 循环可用于迭代直到满足条件。如果你输入非常不切实际的概率和目标值,我猜它可能会变成一个失控的函数,所以请考虑一下自己被警告:)

FOO <- function(probs, target) {
  out <- rbinom(length(probs), 1, probs)

  while (sum(out) != target) {

    out <- rbinom(length(probs), 1, probs)
  }
  return(out)
}

FOO(概率,目标 = 5)

> FOO(probs, target = 5)  
 [1] 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 1 0

【讨论】:

  • +1 @Chase,很好的答案和良好的油漆重新while() 循环。可以解决这个问题,但会产生更复杂的功能......
  • 谢谢!这有效,但需要很长时间。我正在运行 1000 个模拟,每个模拟的目标为 5、10、15...等,每个周期大约需要 4 个小时。让我尝试其他方法之一并回复您。
  • @Laura - Gavin 和 James 的答案都比我的聪明一点,但也许这个简单的实现说明了如何使用 while 循环概念。
  • 确实!这是非常有用的。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-25
  • 2017-11-20
相关资源
最近更新 更多