首页 > 解决方案 > 在 R 中,将一个向量随机分成 k 个块?

问题描述

我在这里看到了关于“将向量 X 拆分为 R 中的 Y 块”问题的许多变体。例如:这里这里只有两个。所以,当我意识到我需要将一个向量分成 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,所以我的意思是除此之外。

标签: rperformancevectorvectorization

解决方案


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

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)
}

运行基准测试,我认为其中任何一个都足够快(单位是微秒)。

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()功能。


推荐阅读