我想在数据帧的给定行块之间分别对每列进行随机重新排序。行块是连续的,如下所示:
mylist=list(1:50,51:52,53:102,103:128,129:154,155:180,181:206,207:232,233:258,259:284,285:310,311:336,337:362,363:388,389:414,415:440,441:466,467:492,493:518,519:544,545:570,571:596,597:622,623:648,649:674,675:700)
假设我有一个名为dat的data.frame。它是700行和50列。所以基本上,对于这26个行块中的每一个,我希望每列都随机重新排序。
具有较小data.frame的示例可以是A =
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
5 5 5 5 5
6 6 6 6 6
7 7 7 7 7
8 8 8 8 8
9 9 9 9 9
其中每个行bin如下:
mylist=list(1:2,3:6,7:9)
可能导致重新排序的数据帧B =
1 2 1 1 1
2 1 2 2 2
3 4 3 5 3
4 6 4 3 4
5 5 5 6 5
6 3 6 4 6
8 9 8 7 9
9 7 9 8 8
7 8 7 9 7
谢谢。
答案 0 :(得分:1)
你可以试试这个:
# create a 'blocking variable'
block <- rep(x = seq_along(mylist), times = sapply(mylist, length))
# within each block, loop over columns and 'shuffle' each column using `sample`
set.seed(1)
B <- do.call(rbind.data.frame,
by(A, block, function(dat){
sapply(dat, function(x) sample(x))
})
)
B
# V1 V2 V3 V4 V5
# 1.1 1 2 1 2 2
# 1.2 2 1 2 1 1
# 2.1 3 6 4 5 3
# 2.2 6 4 5 3 4
# 2.3 4 5 6 6 5
# 2.4 5 3 3 4 6
# 3.1 8 7 9 8 9
# 3.2 9 8 7 9 8
# 3.3 7 9 8 7 7
在@Ananda Mahto的评论之后 更新:
如果B
不 成为数据框,而您对矩阵感到满意,do.call(rbind.data.frame,
可以替换为do.call(rbind,
,这会更快。
答案 1 :(得分:1)
这是一种方法。它不需要首先存在名为“A”的data.frame
,并且像BrodieG的答案一样,假设“mylist”中没有孔或重复。
这将生成一个矩阵,其中列数由Ncol
指定。
Ncol <- 50 # Number of columns
A1 <- seq_along(unlist(mylist, use.names = FALSE))
do.call(rbind, # ^^ Generate a sequence
lapply(mylist, function(x) { # Traverse the list
replicate(Ncol, sample(A1[x])) # Use replicate with sample
}))
此处它适用于您的小清单:
mylist <- list(1:2,3:6,7:9)
set.seed(1) # to be able to reproduce this answer
Ncol <- 5
A1 <- seq_along(unlist(mylist, use.names = FALSE))
do.call(rbind,
lapply(mylist, function(x) {
replicate(Ncol, sample(A1[x]))
}))
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 2 1 2 2
# [2,] 2 1 2 1 1
# [3,] 3 6 4 5 3
# [4,] 6 4 5 3 4
# [5,] 4 5 6 6 5
# [6,] 5 3 3 4 6
# [7,] 8 7 9 8 9
# [8,] 9 8 7 9 8
# [9,] 7 9 8 7 7
另一个需要考虑的选项是“permute”包中的shuffle
。为此,您创建了一个分组变量,正如Henrik在他的答案中所做的那样,并且您将其用作“块”,在其中对给定的值范围进行混洗。
library(permute)
mylist <- list(1:2,3:6,7:9)
block <- how(blocks = rep(seq_along(mylist), sapply(mylist, length)))
shuffle(length(block$blocks), block)
# [1] 2 1 4 5 3 6 7 9 8
您可以轻松使用replicate
来获取包含多列的矩阵:
set.seed(1)
replicate(5, shuffle(length(block$blocks), block))
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 1 1 1 2
# [2,] 2 2 2 2 1
# [3,] 5 3 6 4 5
# [4,] 6 5 3 6 4
# [5,] 3 6 4 5 6
# [6,] 4 4 5 3 3
# [7,] 9 8 7 7 9
# [8,] 8 9 9 8 8
# [9,] 7 7 8 9 7
答案 2 :(得分:0)
这样就可以了解
dat_new<-dat[,unlist(mapply(function(x) sample(x),mylist))]
说明:
sample()从x
中选择一个随机排列mapply(function(x)sample(x),mylist)将sample()应用于单个块
使用unlist()合并结果列表并将其放在dat [,此处]
修改数据证明。
mylist<-list(1:2,3:5)
dat<-data.frame(a=1:2,b=2:3,c=3:4,d=4:5,e=5:6)
dat包含
a b c d e
1 1 2 3 4 5
2 2 3 4 5 6
应在(a,b)和(c,d,e)之间进行重新洗牌
dat_new<-dat[,unlist(mapply(function(x) sample(x),mylist))]
dat_new包含
b a d c e
1 2 1 4 3 5
2 3 2 5 4 6
答案 3 :(得分:0)
假设你的mylist
是完全连续的,没有漏洞或重复(即unlist(mylist) == 1:length(unlist(mylist))
,就像你提供的那个一样,那么你可以相对轻松地使用任何“分裂 - apply-combine“methods。这是一个data.table
实现,我们首先创建一个拆分索引,它只是按照该组中的项目数重复每个组的标签,然后按组拆分/重新排序
dt[, split.idx:=unlist(
lapply(
mylist, # for each item in mylist
function(x) rep(paste0(range(x), collapse="-"), length(x)) # create "min-max" label repeated `length` times
) ) ]
dt[, lapply(.SD, sample), by=split.idx] # for each group (`.SD`), cycle through each column and `sample`
生成(注意,我将结果子集化为易于显示的内容):
split.idx V1 V2 V3 V4 V5 V6 V7 V8 V9
1: 1-50 14 8 9 40 42 47 4 38 5
2: 1-50 49 11 39 31 15 4 17 18 25
3: 1-50 29 25 11 5 37 12 11 29 11
4: 1-50 6 7 37 23 28 21 22 45 36
5: 1-50 16 30 4 46 35 17 46 47 47
6: 1-50 3 21 22 20 14 40 6 2 44
7: 51-52 51 51 51 52 52 51 52 52 52
8: 51-52 52 52 52 51 51 52 51 51 51
9: 53-102 71 61 56 87 77 81 78 69 64
10: 53-102 101 73 59 92 63 59 101 84 96
11: 53-102 74 98 75 62 60 85 73 70 97
12: 53-102 73 94 64 79 95 77 81 74 53
13: 53-102 88 63 71 86 57 82 61 61 93
14: 53-102 91 65 76 96 82 76 77 62 68
15: 53-102 97 55 68 74 83 64 91 77 91
16: 53-102 96 68 96 98 86 83 82 54 102
17: 53-102 64 62 73 64 79 65 60 90 57
18: 53-102 63 99 74 78 56 68 59 81 79
19: 53-102 93 79 78 71 85 57 88 91 65
20: 53-102 84 101 72 65 87 56 65 64 61
21: 53-102 76 81 99 63 96 73 67 67 63
split.idx V1 V2 V3 V4 V5 V6 V7 V8 V9
你可以清楚地看到,特别是51-52组,只有51-52的值。以下是我使用的数据:
library(data.table)
set.seed(1)
dt <- data.table(replicate(50, 1:700))