如何编写 R 函数来创建基于多列的每个子组?

How to write R function to create every subgroup based on multiple columns?

我正在努力在 R 中创建一个函数,该函数将接受数据集和列,并输出由所有这 3 列过滤的数据集的每个排列。

我的数据集看起来像

structure(list(name = c("Peter Doe", "John Gary", "Elsa Johnson", 
"Mary Poppins", "Jesse Bogart"), sex = c("Male", "Male", "Female", 
"Female", "Male"), class = c("Honors", "Core", "Core", "Honors", 
"Honors"), grade = c("A", "A", "A", "B", "C")), class = c("tbl_df", 
"tbl", "data.frame"), row.names = c(NA, -5L))

我试着在这里形象化我的目标:

我希望根据这张地图所遵循的路径创建新变量(例如 male_honors_a <- 按这些列值过滤的数据集)我想我可以使用粘贴功能来做到这一点,但我在这里也不确定。但更重要的是,我正在努力解决如何将 for 循环放在能够根据列的唯一值进行过滤的函数中。

我编写了一个函数来单独创建每个子组,但无法弄清楚如何将它们组合在一起。

subgroups <- function(df, filters, group = "none", name = ""){
  listofdfs <- list()
  for (i in filters) {
    subgroups <- unique(df[[i]])
    for (j in subgroups){
      x <- df[df[i] == j,]
      listofdfs[[paste(name,j, sep = "")]] <- x
    }
  }
  if (group != "none"){
    return(listofdfs[[group]])
  }
  else {
  return(listofdfs)}
}

subgroups(df, c("sex", "class", "grade"))

我希望 运行 subgroups(df, c("sex", "class")),我的输出将是数据帧列表:

list(male_honors, male_core, female_honors, female_core)

其中 male_honors 元素是

# A tibble: 2 × 4
  name         sex   class  grade
1 Peter Doe    Male  Honors A    
2 Jesse Bogart Male  Honors C   

非常感谢任何帮助!

tidyr::nest() 直接执行此操作。请注意,对于 grouping/nesting 变量的每个组合,data 单元格中都会整齐地塞入一个 tibble。我通过 (a) 删除与分组无关的方面(如过滤器)和 (b) 使 groups 默认为空字符向量,对您的函数进行了一些修改,因此如果未传递任何内容,则不会对任何内容进行分组。

此外,名字(例如,男性荣誉)很容易通过变量值检索。这通常比从 变量名称 .

中检索值有用得多

这对您有用吗?

subgroups <- function(df, groups = character(0)) {
  df |> 
    tidyr::nest(data = -groups)
}
> subgroups(ds, c("class", "sex"))
# # A tibble: 4 × 3
#   sex    class  data            
#   <chr>  <chr>  <list>          
# 1 Male   Honors <tibble [2 × 2]>
# 2 Male   Core   <tibble [1 × 2]>
# 3 Female Core   <tibble [1 × 2]>
# 4 Female Honors <tibble [1 × 2]>

> subgroups(ds, c("sex"))
# # A tibble: 2 × 2
#   sex    data            
#   <chr>  <list>          
# 1 Male   <tibble [3 × 3]>
# 2 Female <tibble [2 × 3]>

> subgroups(ds)
# # A tibble: 1 × 1
#   data            
#   <list>          
# 1 <tibble [5 × 4]>

其他资源:tidyr 的 Nested data 插图

您可以创建用于过滤的列键。键的唯一性可用于循环遍历数据框的每个子集。这是一个解决方案,您的数据为 df,所需的列表结果为 l

library(dplyr)
#make a key (constructed of 2 or more column values)
df<- df  |>  mutate(key = paste0(sex, "_", class))
#get the unqiue keys
keys<-unique(df$key)
#make an empty list
l<-list()
#loop through unique keys to filter your df, removing the key column 
for(x in 1:length(keys)){
  l[[x]]<-df[df$key ==keys[x],]  |> select(!key)
}
#name list elements
names(l)<-tolower(keys)
# your desired result
l

写成一个函数,看起来像这样:

subgroups <- function(df, groups = character(0)){
#make a key vector 
v <- df  |>  select(groups) 
v <- do.call(paste, c(v, sep = "_"))
#get unqiue keys
keys<-unique(v)
#make an empty list
l<-list()
#loop through unique keys to filter, removing the key column 
for(x in 1:length(keys)){
  l[[x]]<-df[v %in% keys[x],] |> select(!key)
}
return(l)
}

#example call
subgroups(df, c("sex", "class"))