在子数组之间移动行

Moving rows between subarrays

我有许多子数组,比如 2 个(为简单起见),每个子数组的行数和列数相同。子数组中的每个点都被 [1, 10] 中的一个数字占据。

我想做的是根据某个移动速率 m = [0, 1] 在子数组之间随机移动行。 m = 0 对应于没有移动,而 m = 1 意味着可以移动所有子数组中的任何行。

我的灵感来自:

但我的问题与此略有不同。我知道这里需要 sample() 。

有没有简单的方法来完成这个?

这不行,但我相信无论如何我都在正确的轨道上。

m <- 0.2

 a <- array(dim = c(5, 5, 2)) # 5 rows, 5 columns, 2 subarrays

res <- rep(sample(nrow(a), size = ceiling(nrow(a)*m), replace = FALSE)) # sample 20% of rows from array a. 

如有任何帮助,我们将不胜感激。

如果你可以使用 matrix (2-dim array) 就容易多了。

set.seed(2)
m <- 0.2
d <- c(10, 4)
a <- array(sample(prod(d)), dim = d)
a
#       [,1] [,2] [,3] [,4]
#  [1,]    8   17   14    1
#  [2,]   28   37   40   26
#  [3,]   22   38   16   29
#  [4,]    7   35    3   32
#  [5,]   34   11   23    4
#  [6,]   36   33   19   31
#  [7,]    5   24   30   13
#  [8,]   39    6   27   25
#  [9,]   15   10   12    9
# [10,]   18    2   21   20

(我将再次设置种子,以便方便地给我一些 "interesting" 来展示。)

set.seed(2)
ind <- which(runif(d[1]) < m)
ind
# [1] 1 4 7

第一个随机性 runifm 进行比较,并生成 可能会改变 的索引。第二个随机性,下面的 sample,采用这些索引并可能对它们重新排序。 (在这种情况下,它会将“1,4,7”重新排序为“4,1,7”,这意味着第三行可能会更改的行将保持不变。)

a[ind,] <- a[sample(ind),]
a
#       [,1] [,2] [,3] [,4]
#  [1,]    7   35    3   32  # <-- row 4
#  [2,]   28   37   40   26
#  [3,]   22   38   16   29
#  [4,]    8   17   14    1  # <-- row 1
#  [5,]   34   11   23    4
#  [6,]   36   33   19   31
#  [7,]    5   24   30   13  # <-- row 7, unchanged
#  [8,]   39    6   27   25
#  [9,]   15   10   12    9
# [10,]   18    2   21   20

请注意,这是 概率,这意味着 0.2 的概率并不能保证你有 20%(甚至 any)将交换行。

(因为我猜你真的很想保留你的 3-dim(甚至 n-dim)array,你也许可以使用 apermarray <--> matrix 之间转移。)

编辑 1

作为概率使用 runif 的替代方法,您可以使用:

ind <- head(sample(d[1]),size=d[1]*m) 

更接近“20%”的目标。由于 d[1]*m 通常不是整数,head 默默地 truncates/floors 数字,因此您将获得价格合适的赢家:最接近但不超过您想要的百分比。

编辑 2

一种可逆的方法,用于将 n 维数组转换为矩阵并再次转换回来。 警告:虽然逻辑看起来很可靠,但我的测试只包含几个数组。

array2matrix <- function(a) {
  d <- dim(a)
  ind <- seq_along(d)
  a2 <- aperm(a, c(ind[2], ind[-2]))
  dim(a2) <- c(d[2], prod(d[-2]))
  a2 <- t(a2)
  attr(a2, "origdim") <- d
  a2
}

反转使用 "origdim" 属性(如果仍然存在);只要您对矩阵的修改不清除其属性,这就会起作用。 (简单的行交换不会。)

matrix2array <- function(m, d = attr(m, "origdim")) {
  ind <- seq_along(d)
  m2 <- t(m)
  dim(m2) <- c(d[2], d[-2])
  aperm(m2, c(ind[2], ind[-2]))
}

(这两个函数可能应该做更多的错误检查,例如is.null(d)。)

样本运行:

set.seed(2)
dims <- 5:2
a <- array(sample(prod(dims)), dim=dims)

快看:

a[,,1,1:2,drop=FALSE]
# , , 1, 1
#      [,1] [,2] [,3] [,4]
# [1,]   23  109   61   90
# [2,]   84   15   27  102
# [3,]   68   95   83   24
# [4,]   20   53  117   46
# [5,]  110   62   43    8
# , , 1, 2
#      [,1] [,2] [,3] [,4]
# [1,]  118   25   14   93
# [2,]   65   21   16   77
# [3,]   87   82    3   38
# [4,]   92   12   78   17
# [5,]   49    4   75   80

改造:

m <- array2matrix(a)
dim(m)
# [1] 30  4
head(m)
#      [,1] [,2] [,3] [,4]
# [1,]   23  109   61   90
# [2,]   84   15   27  102
# [3,]   68   95   83   24
# [4,]   20   53  117   46
# [5,]  110   62   43    8
# [6,]   67   47    1   54

可逆性证明:

identical(matrix2array(m), a)
# [1] TRUE

编辑 3,"WRAP UP of all code"

创建虚假数据:

dims <- c(5,4,2)
(a <- array(seq(prod(dims)), dim=dims))
# , , 1
#      [,1] [,2] [,3] [,4]
# [1,]    1    6   11   16
# [2,]    2    7   12   17
# [3,]    3    8   13   18
# [4,]    4    9   14   19
# [5,]    5   10   15   20
# , , 2
#      [,1] [,2] [,3] [,4]
# [1,]   21   26   31   36
# [2,]   22   27   32   37
# [3,]   23   28   33   38
# [4,]   24   29   34   39
# [5,]   25   30   35   40
(m <- array2matrix(a))
#       [,1] [,2] [,3] [,4]
#  [1,]    1    6   11   16
#  [2,]    2    7   12   17
#  [3,]    3    8   13   18
#  [4,]    4    9   14   19
#  [5,]    5   10   15   20
#  [6,]   21   26   31   36
#  [7,]   22   27   32   37
#  [8,]   23   28   33   38
#  [9,]   24   29   34   39
# [10,]   25   30   35   40
# attr(,"origdim")
# [1] 5 4 2

行的随机交换。我这里用了 50%。

pct <- 0.5
nr <- nrow(m)
set.seed(3)
(ind1 <- sample(nr, size = ceiling(nr * pct)))
# [1] 2 8 4 3 9
(ind2 <- sample(ind1))
# [1] 3 2 9 8 4
m[ind1,] <- m[ind2,]
m
#       [,1] [,2] [,3] [,4]
#  [1,]    1    6   11   16
#  [2,]    3    8   13   18
#  [3,]   23   28   33   38
#  [4,]   24   29   34   39
#  [5,]    5   10   15   20
#  [6,]   21   26   31   36
#  [7,]   22   27   32   37
#  [8,]    2    7   12   17
#  [9,]    4    9   14   19
# [10,]   25   30   35   40
# attr(,"origdim")
# [1] 5 4 2

(请注意,我在这里预先制作了 ind1ind2,主要是为了查看内部发生了什么。您可以将 m[ind2,] 替换为 m[sample(ind1),]同样的效果。)

顺便说一句:如果我们改为使用 2 的种子,我们会注意到 2 行 没有交换:

set.seed(2)
(ind1 <- sample(nr, size = ceiling(nr * pct)))
# [1]  2  7  5 10  6
(ind2 <- sample(ind1))
# [1]  6  2  5 10  7

正因如此,我选择了3个种子进行演示。但是,这可能会使事情看起来不起作用。缺少更多控制代码,sample 不能确保位置发生变化:期望 "randomly swap rows" 可以随机选择将第 2 行移动到第 2 行当然是合理的。举个例子:

set.seed(267)
(ind1 <- sample(nr, size = ceiling(nr * pct)))
# [1] 3 6 5 7 2
(ind2 <- sample(ind1))
# [1] 3 6 5 7 2

先随机选择五行,然后将它们随机重新排序为不变的顺序。 (我建议,如果你想强制它们都是运动,你应该问一个新的问题,询问是否只是强制sample向量改变。 )

无论如何,我们可以通过第二个函数恢复原来的维度:

(a2 <- matrix2array(m))
# , , 1
#      [,1] [,2] [,3] [,4]
# [1,]    1    6   11   16
# [2,]    3    8   13   18
# [3,]   23   28   33   38
# [4,]   24   29   34   39
# [5,]    5   10   15   20
# , , 2
#      [,1] [,2] [,3] [,4]
# [1,]   21   26   31   36
# [2,]   22   27   32   37
# [3,]    2    7   12   17
# [4,]    4    9   14   19
# [5,]   25   30   35   40

阵列的第一个平面,第1行和第5行不变;在第二个平面中,第 1、2 和 5 行没有变化。五行相同,五行移动(但每行内其他方面不变)。