根据特定模式在数据框中置换行

时间:2017-03-03 14:47:08

标签: r

我的数据框如下所示:

library(dplyr)

df <- data.frame(grp = rep(letters[1:3], each = 3)) %>%
          mutate(val = paste0(grp, 1:3))

  grp val
1   a  a1
2   a  a2
3   a  a3
4   b  b1
5   b  b2
6   b  b3
7   c  c1
8   c  c2
9   c  c3

我希望将df的行顺序置换为grp,这样每3个连续行必须按随机顺序包含a,b和c。以下是输出应如何显示的三个示例:

  grp val        grp val        grp val
1   a  a1      9   c  c3      7   c  c1
8   c  c2      2   a  a2      1   a  a1
4   b  b1      5   b  b2      6   b  b3
3   a  a3      4   b  b1      9   c  c3
9   c  c3      3   a  a3      3   a  a3
6   b  b3      7   c  c1      4   b  b1
7   c  c1      6   b  b3      5   b  b2
2   a  a2      8   c  c2      8   c  c2
5   b  b2      1   a  a1      2   a  a2

理想情况下,该解决方案也适用于以下形式的类似数据框:

df <- data.frame(grp = rep(letters[1:x], each = y)) %>%
          mutate(val = paste0(grp, 1:(x*y)))
# where x and y may be natural numbers

我试图使用group_bysample_n函数,但没有成功。

2 个答案:

答案 0 :(得分:2)

这是一个dplyr方法:

df %>% 
  sample_frac(1) %>%                  # order randomly
  group_by(grp) %>%                   # group by "grp" column 
  group_by(row = row_number()) %>%    # group by 1:n in each "grp" group
  sample_frac(1)                      # sample all rows from these groups

之后,您可以使用%>% ungroup() %>% select(-row)扩展管道以删除新创建的分组列。

两次采样运行的结果如下

replicate(2, sample_frac(df, 1) %>% group_by(grp) %>% 
             group_by(row = row_number()) %>%
             sample_frac(1), simplify = FALSE)
# [[1]]
# Source: local data frame [9 x 3]
# Groups: row [3]
# 
#     grp   val   row
#   <fctr> <chr> <int>
# 1      b    b1     1
# 2      c    c1     1
# 3      a    a2     1
# 4      a    a1     2
# 5      c    c2     2
# 6      b    b2     2
# 7      b    b3     3
# 8      c    c3     3
# 9      a    a3     3
# 
# [[2]]
# Source: local data frame [9 x 3]
# Groups: row [3]
# 
#     grp   val   row
#   <fctr> <chr> <int>
# 1      c    c3     1
# 2      a    a3     1
# 3      b    b3     1
# 4      a    a1     2
# 5      b    b2     2
# 6      c    c1     2
# 7      c    c2     3
# 8      a    a2     3
# 9      b    b1     3

答案 1 :(得分:1)

以下是使用replicatesamplerept的基本R方法。这假设组中的单元数与组数相同。

permuter <- function(n) c(t(replicate(n, sample(n))) + (rep(seq_len(n)-1) * n))

这使用replicate来抽样每个组中的元素数量,从而有效地排序组内元素的选择。矩阵输出被添加到调整组数的序列中。由此产生的矩阵被转换为在组排序之间,然后转换为列出行的新位置的向量。

permuter(3)
[1] 1 5 7 2 6 9 3 4 8

要重新排序,只需将结果提供给[

df[permuter(3), ]
  grp val
1   a  a1
5   b  b2
7   c  c1
2   a  a2
6   b  b3
9   c  c3
3   a  a3
4   b  b1
8   c  c2

请注意,我使用set.seed(1234)在两个实例中重现了该函数的相同输出。

更灵活的排列

在具有不同数量的组与组内大小(例如3组,每组有4个单元)的情况下,以下更灵活的功能将起作用。

permuterFlex <- function(numG, wSize) {
  c(t(replicate(numG, sample(wSize)) + rep(seq_len(numG)-1, each=wSize) * (wSize)))
}

这里,numG是组的数量,wSize是组内的单位数。要查看此内容,请复制上述结果。

set.seed(1234)
permuterFlex(3, 3)
[1] 1 5 7 2 6 9 3 4 8