使用 R 根据条件随机排列数据框中的行

Shuffle rows in a dataframe based on a condition using R

我正在尝试使用 R 根据条件随机排列数据框中的所有行。

这是我的数据框示例:

l <- c("Ana", "Maria", "Hanne", "Liam","Sarah","Ella")
c <- c(1,1,2,3,3,2)
df <- as.data.frame(cbind(l,c))
colnames(df) <- c("Name", "ClassNr")

我的目标是打乱所有行,确保 3 行的每个序列都具有来自不同 ClassNr 的名称。 我尝试了以下方法:

set.seed(55)
df[sample(nrow(df), 3),]

此代码给了我 3 个随机行,但我需要添加条件,即在 3 行的每个“块”中不重复给定的 ClassNr。此外,我需要再次重复此操作以将完整的名称列表包含在“随机数据框”中。

输出示例为:

  Name ClassNr
1 Ana        1
2 Ella       2
3 Liam       3
4 Maria      1
5 Hanne      2
6 Sarah      3

解决这个问题的最佳方法是什么?

我曾尝试使用此示例,但未能理解解决方案以适用于我的问题:

谢谢

为什么不简单地打乱你的名字,然后将 1:3 的序列追加两次?但是我其实不太明白你要达到什么目的,所以也许你可以更清楚一点。

(注意:我在这里按字母顺序排列名称是为了说明,但这在现实生活中没有意义,因为它总是导致相同的结果)

set.seed(1)
Name <- sort(sample(l, 6, replace = FALSE))
ClassNr <- rep(1:3, 2)

shuffled_df <- data.frame(Name, ClassNr)

shuffled_df

            Name   ClassNr
1            Ana         1
2           Ella         2
3          Hanne         3
4           Liam         1
5          Maria         2
6          Sarah         3

这是一个相当简单的方法,但可能不是最短的方法。

library(dplyr)

l <- c("Ana", "Maria", "Hanne", "Liam","Sarah","Ella")
c <- c(1,1,2,3,3,2)
df <- as.data.frame(cbind(l,c))
colnames(df) <- c("Name", "ClassNr")

正在创建一个包含 3 个数据帧的列表 - 每个 class。此时在 3 个数据帧中的每一个中,行都被打乱。 index 列已添加以进一步排序:

lst = list()

for (i in unique(df$ClassNr)) {  
  dat <- df %>% 
    filter(ClassNr == i)
  
  rows <- sample(nrow(dat))
  dat <- dat[rows, ] 
  dat <- dat %>% mutate(index = row_number())
  
  lst[[i]] = dat
}

将 3 个打乱的数据帧连接到最终的 output 数据帧中。按indexClassNr排列:

output <- data.frame()

for (i in seq(1:length(lst))) {
  output <- output %>% rbind(lst[[i]])
}

output <- output %>%
  arrange(index, ClassNr) %>%
  select(-index)

index排列确保1-2-3顺序。你可以这样想:用 Class 1 从 df 中取出第一行,用 Class 2 添加 df 的第一行,然后用 Class 3 添加第一行。然后添加第二行来自第一、第二和第三数据集等

结果:

    Name ClassNr
2  Maria       1
21  Ella       2
22  Liam       3
1    Ana       1
11 Hanne       2
12 Sarah       3

你可以试试这个:

library(purrr)
library(tidyr)
library(dplyr)

df %>% 
  split(f = as.factor(.$ClassNr)) %>% 
  map_dfr(~sample(.x$Name)) %>% 
  pivot_longer(everything(),
               names_to = "ClassNr",
               values_to = "Name")

返回(例如)

# A tibble: 6 x 2
  ClassNr Name
  <chr>   <chr>
1 1       Ana  
2 2       Ella 
3 3       Sarah
4 1       Maria
5 2       Hanne
6 3       Liam 
  • 我们首先根据 ClassNr 将数据分组。那是 split 部分。现在我们有三个列表(每个 class 一个列表)。
  • 接下来我们获取每个列表并对元素进行采样,这基本上是独立地洗牌每个列表并将结果绑定在一起作为数据帧。
  • 最后我们将这个数据帧转换为长格式。

注意:如果每个 class 中的名称数量不同,此方法很可能会失败。

我的解决方案是使用dplyrarrange()来排列ClassNr,然后排列在一个重复的数字序列上:

df %>% 
  arrange(ClassNr) %>% 
  arrange(rep(1:(ceiling(nrow(df)/3)), 3)[1:nrow(df)]) 

   Name ClassNr
1   Ana       1
2 Hanne       2
3  Liam       3
4 Maria       1
5  Ella       2
6 Sarah       3

需要对排序序列进行一些操作,以防行数不能被 3 整除。例如:

    Name ClassNr
1    Ana       1
2  Hanne       2
3   Liam       3
4  Maria       1
5   Ella       2
6  Sarah       3
7  Other       1
8 Other2       2