在 R 中无重复地改组数据帧
Shuffling a dataframe in R with no repeats
有没有人知道如何在 R 中编写数据集随机播放脚本,这样如果我在数据框中有 25 个数字(5 行 x 5 列),并且我分别随机播放 25 次,每个数字都出现在每个位置恰好一次?
因此它不是完全随机的,至少在第一次洗牌之后不是,因为随着每次洗牌,任何数字的潜在位置都会减少。
谢谢!
我将在 3 x 3 数据集上演示解决方案。我要做的第一件事是将 data.frame 转换为矩阵,以便能够轻松应用排列。
假设我们有一个 3x3 矩阵:
set.seed(1)
m <- matrix(sample(1:100, 9), nrow = 3)
m
#> [,1] [,2] [,3]
#> [1,] 68 34 14
#> [2,] 39 87 82
#> [3,] 1 43 59
然后每个洗牌可以通过数字 1 到 9 的排列来定义。
shuffle <- c(9, 4, 7, 1, 8, 3, 2, 5, 6)
matrix(m[shuffle], nrow = 3)
#> [,1] [,2] [,3]
#> [1,] 59 68 39
#> [2,] 34 82 87
#> [3,] 14 1 43
因此我们的任务是生成 9 个这样的排列,其中每个数字在每个位置上只出现一次。例如。第一次洗牌c(9, 4, 7, 1, 8, 3, 2, 5, 6)
,我们不能c(9, 2, 7, 3, 8, 5, 4, 6, 1)
,因为9已经排在第一位,7排在第三位,8排在第五位。
基本上我们需要的是 9 x 9 latin square。幸好有这样的包:
library(magic)
#> Loading required package: abind
set.seed(1)
shuffles_matrix <- rlatin(9)
shuffles_matrix
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#> [1,] 6 5 4 2 3 9 8 1 7
#> [2,] 4 2 7 6 9 8 1 3 5
#> [3,] 8 3 1 5 2 7 9 4 6
#> [4,] 5 1 9 7 6 2 4 8 3
#> [5,] 3 6 5 1 8 4 7 9 2
#> [6,] 9 7 8 3 1 6 5 2 4
#> [7,] 7 9 3 4 5 1 2 6 8
#> [8,] 2 8 6 9 4 5 3 7 1
#> [9,] 1 4 2 8 7 3 6 5 9
现在我们可以将这个正方形的每一行视为我们原始 3x3 矩阵的洗牌:
shuffles <- split(shuffles_matrix, 1:9)
shuffles
#> $`1`
#> [1] 6 5 4 2 3 9 8 1 7
#>
#> $`2`
#> [1] 4 2 7 6 9 8 1 3 5
#>
#> $`3`
#> [1] 8 3 1 5 2 7 9 4 6
#>
#> $`4`
#> [1] 5 1 9 7 6 2 4 8 3
#>
#> $`5`
#> [1] 3 6 5 1 8 4 7 9 2
#>
#> $`6`
#> [1] 9 7 8 3 1 6 5 2 4
#>
#> $`7`
#> [1] 7 9 3 4 5 1 2 6 8
#>
#> $`8`
#> [1] 2 8 6 9 4 5 3 7 1
#>
#> $`9`
#> [1] 1 4 2 8 7 3 6 5 9
这就是我们将这些洗牌应用到矩阵的方式:
library(purrr)
shuffles %>%
map(~matrix(m[.], nrow = 3))
#> $`1`
#> [,1] [,2] [,3]
#> [1,] 43 39 82
#> [2,] 87 1 68
#> [3,] 34 59 14
#>
#> $`2`
#> [,1] [,2] [,3]
#> [1,] 34 43 68
#> [2,] 39 59 1
#> [3,] 14 82 87
#>
#> $`3`
#> [,1] [,2] [,3]
#> [1,] 82 87 59
#> [2,] 1 39 34
#> [3,] 68 14 43
#>
#> $`4`
#> [,1] [,2] [,3]
#> [1,] 87 14 34
#> [2,] 68 43 82
#> [3,] 59 39 1
#>
#> $`5`
#> [,1] [,2] [,3]
#> [1,] 1 68 14
#> [2,] 43 82 59
#> [3,] 87 34 39
#>
#> $`6`
#> [,1] [,2] [,3]
#> [1,] 59 1 87
#> [2,] 14 68 39
#> [3,] 82 43 34
#>
#> $`7`
#> [,1] [,2] [,3]
#> [1,] 14 34 39
#> [2,] 59 87 43
#> [3,] 1 68 82
#>
#> $`8`
#> [,1] [,2] [,3]
#> [1,] 39 59 1
#> [2,] 82 34 14
#> [3,] 43 87 68
#>
#> $`9`
#> [,1] [,2] [,3]
#> [1,] 68 82 43
#> [2,] 34 14 87
#> [3,] 39 1 59
我认为 Iaroslav 的回答非常好。我使用了一些不同的函数来基本上做同样的事情,所以我想我会分享一些其他的代码。基本上我还创建了一个拉丁方阵,但我没有意识到这是名字。我用
做到了
roll <- function(x, i) {
if (i==0) return(x)
c(x[-(1:i)], x[1:i])
}
m <- sapply(0:24, function(i) roll(1:25, i))
这里我只用了数字1:25。它创建一个矩阵,其中每一行或每一列都是一组可用于排列您的值的索引。如果看起来太有序,还可以用另一个辅助函数
打乱矩阵的行列
shuffle_mat <- function(x, N=50, margin=c(1,2)) {
mg <- sample(margin, N, replace=TRUE)
n_row_swap = sum(mg==1)
sr <- replicate(n_row_swap, sample.int(nrow(x), 2))
for(i in 1:ncol(sr)) {
x[sr[,i],]<-x[rev(sr[,i]),]
}
n_col_swap = sum(mg==2)
sc <- replicate(n_col_swap, sample.int(ncol(x), 2))
for(i in 1:ncol(sc)) {
x[,sc[,i]]<-x[,rev(sc[,i])]
}
x
}
rr <- shuffle_mat(m)
然后您可以再次将这些 rows/columns 中的每一个组成一个 5x5 矩阵。
有没有人知道如何在 R 中编写数据集随机播放脚本,这样如果我在数据框中有 25 个数字(5 行 x 5 列),并且我分别随机播放 25 次,每个数字都出现在每个位置恰好一次?
因此它不是完全随机的,至少在第一次洗牌之后不是,因为随着每次洗牌,任何数字的潜在位置都会减少。
谢谢!
我将在 3 x 3 数据集上演示解决方案。我要做的第一件事是将 data.frame 转换为矩阵,以便能够轻松应用排列。
假设我们有一个 3x3 矩阵:
set.seed(1)
m <- matrix(sample(1:100, 9), nrow = 3)
m
#> [,1] [,2] [,3]
#> [1,] 68 34 14
#> [2,] 39 87 82
#> [3,] 1 43 59
然后每个洗牌可以通过数字 1 到 9 的排列来定义。
shuffle <- c(9, 4, 7, 1, 8, 3, 2, 5, 6)
matrix(m[shuffle], nrow = 3)
#> [,1] [,2] [,3]
#> [1,] 59 68 39
#> [2,] 34 82 87
#> [3,] 14 1 43
因此我们的任务是生成 9 个这样的排列,其中每个数字在每个位置上只出现一次。例如。第一次洗牌c(9, 4, 7, 1, 8, 3, 2, 5, 6)
,我们不能c(9, 2, 7, 3, 8, 5, 4, 6, 1)
,因为9已经排在第一位,7排在第三位,8排在第五位。
基本上我们需要的是 9 x 9 latin square。幸好有这样的包:
library(magic)
#> Loading required package: abind
set.seed(1)
shuffles_matrix <- rlatin(9)
shuffles_matrix
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
#> [1,] 6 5 4 2 3 9 8 1 7
#> [2,] 4 2 7 6 9 8 1 3 5
#> [3,] 8 3 1 5 2 7 9 4 6
#> [4,] 5 1 9 7 6 2 4 8 3
#> [5,] 3 6 5 1 8 4 7 9 2
#> [6,] 9 7 8 3 1 6 5 2 4
#> [7,] 7 9 3 4 5 1 2 6 8
#> [8,] 2 8 6 9 4 5 3 7 1
#> [9,] 1 4 2 8 7 3 6 5 9
现在我们可以将这个正方形的每一行视为我们原始 3x3 矩阵的洗牌:
shuffles <- split(shuffles_matrix, 1:9)
shuffles
#> $`1`
#> [1] 6 5 4 2 3 9 8 1 7
#>
#> $`2`
#> [1] 4 2 7 6 9 8 1 3 5
#>
#> $`3`
#> [1] 8 3 1 5 2 7 9 4 6
#>
#> $`4`
#> [1] 5 1 9 7 6 2 4 8 3
#>
#> $`5`
#> [1] 3 6 5 1 8 4 7 9 2
#>
#> $`6`
#> [1] 9 7 8 3 1 6 5 2 4
#>
#> $`7`
#> [1] 7 9 3 4 5 1 2 6 8
#>
#> $`8`
#> [1] 2 8 6 9 4 5 3 7 1
#>
#> $`9`
#> [1] 1 4 2 8 7 3 6 5 9
这就是我们将这些洗牌应用到矩阵的方式:
library(purrr)
shuffles %>%
map(~matrix(m[.], nrow = 3))
#> $`1`
#> [,1] [,2] [,3]
#> [1,] 43 39 82
#> [2,] 87 1 68
#> [3,] 34 59 14
#>
#> $`2`
#> [,1] [,2] [,3]
#> [1,] 34 43 68
#> [2,] 39 59 1
#> [3,] 14 82 87
#>
#> $`3`
#> [,1] [,2] [,3]
#> [1,] 82 87 59
#> [2,] 1 39 34
#> [3,] 68 14 43
#>
#> $`4`
#> [,1] [,2] [,3]
#> [1,] 87 14 34
#> [2,] 68 43 82
#> [3,] 59 39 1
#>
#> $`5`
#> [,1] [,2] [,3]
#> [1,] 1 68 14
#> [2,] 43 82 59
#> [3,] 87 34 39
#>
#> $`6`
#> [,1] [,2] [,3]
#> [1,] 59 1 87
#> [2,] 14 68 39
#> [3,] 82 43 34
#>
#> $`7`
#> [,1] [,2] [,3]
#> [1,] 14 34 39
#> [2,] 59 87 43
#> [3,] 1 68 82
#>
#> $`8`
#> [,1] [,2] [,3]
#> [1,] 39 59 1
#> [2,] 82 34 14
#> [3,] 43 87 68
#>
#> $`9`
#> [,1] [,2] [,3]
#> [1,] 68 82 43
#> [2,] 34 14 87
#> [3,] 39 1 59
我认为 Iaroslav 的回答非常好。我使用了一些不同的函数来基本上做同样的事情,所以我想我会分享一些其他的代码。基本上我还创建了一个拉丁方阵,但我没有意识到这是名字。我用
做到了roll <- function(x, i) {
if (i==0) return(x)
c(x[-(1:i)], x[1:i])
}
m <- sapply(0:24, function(i) roll(1:25, i))
这里我只用了数字1:25。它创建一个矩阵,其中每一行或每一列都是一组可用于排列您的值的索引。如果看起来太有序,还可以用另一个辅助函数
打乱矩阵的行列shuffle_mat <- function(x, N=50, margin=c(1,2)) {
mg <- sample(margin, N, replace=TRUE)
n_row_swap = sum(mg==1)
sr <- replicate(n_row_swap, sample.int(nrow(x), 2))
for(i in 1:ncol(sr)) {
x[sr[,i],]<-x[rev(sr[,i]),]
}
n_col_swap = sum(mg==2)
sc <- replicate(n_col_swap, sample.int(ncol(x), 2))
for(i in 1:ncol(sc)) {
x[,sc[,i]]<-x[,rev(sc[,i])]
}
x
}
rr <- shuffle_mat(m)
然后您可以再次将这些 rows/columns 中的每一个组成一个 5x5 矩阵。