【问题标题】:Split data.frame based on levels of a factor into new data.frames根据因子的级别将 data.frame 拆分为新的 data.frames
【发布时间】:2021-08-01 09:43:51
【问题描述】:

我正在尝试根据因子级别创建单独的 data.frame 对象。所以如果我有:

df <- data.frame(
  x=rnorm(25),
  y=rnorm(25),
  g=rep(factor(LETTERS[1:5]), 5)
)

对于包含相应xy 值的g 的每个级别,如何将df 拆分为单独的data.frames?我可以使用split(df, df$g) 实现大部分目标,但我希望因子的每个级别都有自己的data.frame

最好的方法是什么?

【问题讨论】:

  • 你能解释一下split(df, df$g)有什么问题吗?它返回data.frames 的列表,g 的每个值对应一个。

标签: r dataframe r-faq


【解决方案1】:

我认为split 完全符合您的要求。

请注意,X 是一个数据帧列表,如 str 所见:

X <- split(df, df$g)
str(X)

如果您想要具有组 g 名称的单个对象,您可以将来自 split 的 X 的元素分配给这些名称的对象,尽管当您可以仅从列表 split 索引数据帧时,这似乎是额外的工作创建。

#I used lapply just to drop the third column g which is no longer needed.
Y <- lapply(seq_along(X), function(x) as.data.frame(X[[x]])[, 1:2]) 

#Assign the dataframes in the list Y to individual objects
A <- Y[[1]]
B <- Y[[2]]
C <- Y[[3]]
D <- Y[[4]]
E <- Y[[5]]

#Or use lapply with assign to assign each piece to an object all at once
lapply(seq_along(Y), function(x) {
    assign(c("A", "B", "C", "D", "E")[x], Y[[x]], envir=.GlobalEnv)
    }
)

编辑甚至比使用lapply分配给全局环境更好使用list2env

names(Y) <- c("A", "B", "C", "D", "E")
list2env(Y, envir = .GlobalEnv)
A

【讨论】:

  • 谢谢。这是将使用split 创建的每个data.frame 拆分为我遇到困难的单独的单独对象。这正是我想要的。
【解决方案2】:

由于dplyr 0.8.0,我们也可以使用group_split,它与base::split具有相似的行为

library(dplyr)
df %>% group_split(g)

#[[1]]
# A tibble: 5 x 3
#       x      y g    
#   <dbl>  <dbl> <fct>
#1 -1.21  -1.45  A    
#2  0.506  1.10  A    
#3 -0.477 -1.17  A    
#4 -0.110  1.45  A    
#5  0.134 -0.969 A    

#[[2]]
# A tibble: 5 x 3
#       x      y g    
#   <dbl>  <dbl> <fct>
#1  0.277  0.575 B    
#2 -0.575 -0.476 B    
#3 -0.998 -2.18  B    
#4 -0.511 -1.07  B    
#5 -0.491 -1.11  B  
#....

它还带有参数.keep(默认为TRUE)来指定是否应保留分组列。

df %>% group_split(g, .keep = FALSE)

#[[1]]
# A tibble: 5 x 2
#       x      y
#   <dbl>  <dbl>
#1 -1.21  -1.45 
#2  0.506  1.10 
#3 -0.477 -1.17 
#4 -0.110  1.45 
#5  0.134 -0.969

#[[2]]
# A tibble: 5 x 2
#       x      y
#   <dbl>  <dbl>
#1  0.277  0.575
#2 -0.575 -0.476
#3 -0.998 -2.18 
#4 -0.511 -1.07 
#5 -0.491 -1.11 
#....

base::splitdplyr::group_split 的区别在于group_split 不根据分组来命名列表的元素。所以

df1 <- df %>% group_split(g)
names(df1) #gives 
NULL

df2 <- split(df, df$g)
names(df2) #gives
#[1] "A" "B" "C" "D" "E"

数据

set.seed(1234)
df <- data.frame(
      x=rnorm(25),
      y=rnorm(25),
      g=rep(factor(LETTERS[1:5]), 5)
)

【讨论】:

  • 知道了,但是 group_split 给出了不同的拆分结果?
  • 除了列表的名称,它应该给出与split相同的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-24
相关资源
最近更新 更多