在R中的数据框中的阻塞行之间重新排序随机列

时间:2014-02-25 15:17:25

标签: r permutation

我想在数据帧的给定行块之间分别对每列进行随机重新排序。行块是连续的,如下所示:

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

谢谢。

4 个答案:

答案 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))