在 R 中,将向量随机分成 k 个块?

In R, split a vector randomly into k chunks?

我在这里看到关于“将向量 X 分成 R 中的 Y 块”问题的许多变体。参见示例:here and here 仅表示两个。所以,当我意识到我需要将一个向量分成 Y 块 随机大小 时,我惊讶地发现随机性要求可能是“新的”——我找不到在此处执行此操作的方法。

所以,这是我拟定的内容:

k.chunks = function(seq.size, n.chunks) {
  break.pts = sample(1:seq.size, n.chunks, replace=F) %>% sort() #Get a set of break points chosen from along the length of the vector without replacement so no duplicate selections.
  groups = rep(NA, seq.size) #Set up the empty output vector.
  groups[1:break.pts[1]] = 1 #Set the first set of group affiliations because it has a unique start point of 1.

for (i in 2:(n.chunks)) { #For all other chunks...
    groups[break.pts[i-1]:break.pts[i]] = i #Set the respective group affiliations
    }
    groups[break.pts[n.chunks]:seq.size] = n.chunks #Set the last group affiliation because it has a unique endpoint of seq.size.
    return(groups)
    }

我的问题是:这是不是有点不优雅或效率低下?在我打算做的代码中它会被调用 1000 次,所以效率对我来说很重要。避免 for 循环或必须“手动”设置第一个和最后一个组会特别好。我的另一个问题:是否有逻辑输入可以打破这个?我认识到 n.chunks 不能 > seq.size,所以我的意思不是那个。

对于较小的数字,这应该很快。不过这里有更简洁的方式。

k.chunks2 = function(seq.size, n.chunks) {
  break.pts <- sort(sample(1:seq.size, n.chunks - 1, replace = FALSE))
  break.len <- diff(c(0, break.pts, seq.size))
  
  groups <- rep(1:n.chunks, times = break.len)
  return(groups)
}

如果你真的得到大量的组,我认为 sort 将开始花费你的执行时间。所以你可以做这样的事情(可能可以调整得更快)根据比例进行分割。我不确定我对此的感受,因为随着 n.chunks 变得非常大,比例会变得非常小。但是速度更快。

k.chunks3 = function(seq.size, n.chunks) {
  props <- runif(n.chunks)
  grp.props <- props / sum(props)
  
  chunk.size <- floor(grp.props[-n.chunks] * seq.size)
  break.len <- c(chunk.size, seq.size - sum(chunk.size))
  
  groups <- rep(1:n.chunks, times = break.len)
  return(groups)
}

运行一个benchmark,我觉得这些都够快了(单位是微秒)。

n <- 1000
y <- 10

microbenchmark::microbenchmark(k.chunks(n, y),
                               k.chunks2(n, y),
                               k.chunks3(n, y))

Unit: microseconds
            expr  min    lq   mean median    uq   max neval
  k.chunks(n, y) 49.9 52.05 59.613  53.45 58.35 251.7   100
 k.chunks2(n, y) 46.1 47.75 51.617  49.25 52.55 107.1   100
 k.chunks3(n, y)  8.1  9.35 11.412  10.80 11.75  44.2   100

但是随着数字变大,您会注意到有意义的加速(注意单位现在是毫秒)。

n <- 1000000
y <- 100000

microbenchmark::microbenchmark(k.chunks(n, y),
                               k.chunks2(n, y),
                               k.chunks3(n, y))

Unit: milliseconds
            expr     min       lq     mean   median       uq      max neval
  k.chunks(n, y) 46.9910 51.38385 57.83917 54.54310 56.59285 113.5038   100
 k.chunks2(n, y) 17.2184 19.45505 22.72060 20.74595 22.73510  69.5639   100
 k.chunks3(n, y)  7.7354  8.62715 10.32754  9.07045 10.44675  58.2093   100

总而言之,我可能会使用我的 k.chunks2() 功能。

随机可能效率低下,但似乎应该如此。 Random 建议所有输入元素也应该是随机的。因此,考虑从向量 Y 中进行所需的随机选择;似乎应该将努力应用于 Y 的索引和连续的 Y(s),这将是或看起来是随机的。有了足够多的 Y(s) 集,可以看出索引离完全随机还有多远,但也许这不是 material,或者仅仅数千次重复不足以证明这一点。

None 越少,我的感觉是 sample 的两个输入都需要以某种方式 'random' 因为其中一个的确定性降低了另一个的随机性。

my_vector <- c(1:100000) 
sample_1 <- sample(my_vector, 50, replace = FALSE)
sample_2 <- sample(my_vector, 80, replace = FALSE)
full_range <- c(1, sort(unique(sample1,sample2)), 100000)
starts <- full_range[c(TRUE,FALSE)]#[generally](
ends <- full_range[c(FALSE, TRUE)]
!unique(diff(full_range))

并且没有设置种子,我认为不可复制与你在 Y(s) 上随机选择一样接近。这个答案只是建议一种索引 Y 的方法。此后索引的使用可能会遵循 @Adam 的方法。而且,当然,我可能对所有这些都是完全错误的。比我更清醒的随机思考者可能会考虑...