web-dev-qa-db-fra.com

Fractionner data.frame basé sur les niveaux d'un facteur dans de nouveaux data.frames

J'essaie de créer des objets data.frame Séparés en fonction des niveaux d'un facteur. Donc si j'ai:

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

comment puis-je diviser df en data.frame s distincts pour chaque niveau de g contenant les valeurs correspondantes x et y? Je peux obtenir la plupart du chemin en utilisant split(df, df$g), mais j'aimerais que chaque niveau du facteur ait son propre data.frame. Quelle est la meilleure façon de procéder?

Merci.

43
smillig

Je pense que split fait exactement ce que vous voulez.

Notez que X est une liste de trames de données, vue par str:

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

Si vous voulez un objet individuel avec les noms de groupe g, vous pouvez affecter les éléments de X de split aux objets de ces noms, bien que cela semble être un travail supplémentaire lorsque vous pouvez simplement indexer les blocs de données de la liste split crée.

#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)
    }
)

Edit Ou encore mieux que d'utiliser lapply pour attribuer à l'environnement global utiliser list2env:

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

Puisque dplyr 0.8.0, nous pouvons également utiliser group_split qui a un comportement similaire à 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  
#....

Il est également fourni avec l'argument keep (qui est TRUE par défaut) pour spécifier si la colonne groupée doit être conservée ou non.

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 
#....

La différence entre base::split et dplyr::group_split est-ce group_split ne nomme pas les éléments de la liste en fonction du regroupement. Alors

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

tandis que

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

données

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