如果您可以使用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
(我将再次将种子设置为可以方便地向我展示一些“有趣”的东西。)
set.seed(2)
ind <- which(runif(d[1]) < m)
ind
# [1] 1 4 7
第一个随机性,runif
, 与m
并生成索引可能会改变。第二个随机性,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
,你也许可以使用aperm
之间转移array <--> matrix
.)
EDIT 1
作为概率使用的替代方案runif
, 您可以使用:
ind <- head(sample(d[1]),size=d[1]*m)
更接近你的目标“20%”。自从d[1]*m
通常不是整数,head
默默地截断/下限数字,因此您将获得价格合适的获胜者:最接近但不超过您想要的百分比。
EDIT 2
一种可逆变换方法n维数组转换为矩阵,然后再转换回来。Caveat:虽然逻辑看起来很可靠,但我的测试只包括几个数组。
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,“所有代码的总结”
创建虚假数据:
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
(请注意,我预先制作了ind1
and ind2
在这里,主要是为了看看内部发生了什么。您可以更换m[ind2,]
with 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
不确保位置发生变化:期望“随机交换行”可以随机选择将第 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
第一个随机选择五行,然后将它们随机重新排序为不变的顺序。 (我建议如果你想force它们都是运动,你应该问一个新问题,询问只是强迫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 行保持不变。五行相同,五行移动(但每行内其他方面不变)。