shuffle/permutate 逐块向量

shuffle/permutate vector block-wise

我正在尝试打乱一个简单向量的元素,但我想按块执行此操作,因此简单的 sample 操作不起作用。

我的意思是,每 2 个连续值属于一个“块”,我只想打乱这些块,即不打乱各个值。

虽然我想使用 group_by 将我的值组合在一起,但每个块中的值除了一起出现外没有任何共同点。

这是示例向量的样子。 (实向量有超过 5e6 个元素)。

       <------- BLOCK1 ----->  <----- BLOCK 2 ------>    ........
x <- c(0.15055060, 0.69097695, 0.89731929, 0.84515906, 0.54843043, 0.77026955, 0.05127419, 0.33850021, 0.47623089, 0.36896818)

“成功”的随机播放看起来像这样:

                               <------- BLOCK1 ----->                         <----- BLOCK 2 ------>
x <- c(0.05127419, 0.33850021, 0.15055060, 0.69097695, 0.47623089, 0.36896818, 0.89731929, 0.84515906, 0.54843043, 0.77026955)

非常感谢任何关于如何实现这一目标的见解!

只打乱块号 -

inds <- sample(length(x)/2) * 2
x[c(rbind(inds - 1, inds))]
  • length(x)/2x
  • 中的块数
  • 我们sample他们乘以2得到每个块的第二个值
  • 从中减-1得到第一个块值
  • 将它们组合在一起并将其用作 x.
  • 的子集的索引

任何大小的块的一般解决方案是 -

n <- 5000 #block size
inds <- sample(length(x)/n) * n
x[c(sapply(inds, `-`, (n-1):0))]

由于矩阵在 R 中按列存储,我们可以简单地将向量转换为行数等于块大小的矩阵。之后,我们需要做的就是打乱矩阵的列并将其转换回向量。这是一个简单的函数:

ShuffleBlocks <- function(v, size = 2L) {
    size <- as.integer(size)
    stopifnot(length(v) %% size == 0L)
    
    mat <- matrix(v, nrow = size)
    as.vector(mat[, sample(ncol(mat))])
}

在 OP 的示例中调用它:

set.seed(42)
ShuffleBlocks(x)
# [1] 0.15055060 0.69097695 0.47623089 0.36896818 0.05127419 0.33850021 0.54843043 0.77026955 0.89731929 0.84515906
#        x[1]       x[2]        x[9]       x[10]      x[7]       x[8]       x[5]       x[6]       x[3]      x[4]

x
#[1] 0.15055060 0.69097695 0.89731929 0.84515906 0.54843043 0.77026955 0.05127419 0.33850021 0.47623089 0.36896818

对于不同的块大小,这可以顺利推广。例如:

set.seed(321)
ShuffleBlocks(x, size = 5)
# [1] 0.77026955 0.05127419 0.33850021 0.47623089 0.36896818 0.15055060 0.69097695 0.89731929 0.84515906 0.54843043