webentwicklung-frage-antwort-db.com.de

Emulieren Sie split () mit dplyr group_by: Gibt eine Liste von Datenrahmen zurück

Ich habe einen großen Datensatz, der split() in R. drosselt. Ich bin in der Lage, dplyr group_by zu verwenden (was ohnehin ein bevorzugter Weg ist), aber ich kann den resultierenden grouped_df nicht als Liste von Datenrahmen beibehalten, ein Format, das für meine aufeinander folgenden Verarbeitungsschritte erforderlich ist (Ich muss zu SpatialDataFrames und ähnlichem zwingen).

betrachten Sie ein Beispiel-Dataset:

df = as.data.frame(cbind(c("a","a","b","b","c"),c(1,2,3,4,5), c(2,3,4,2,2)))
listDf = split(df,df$V1)

kehrt zurück 

$a
   V1 V2 V3
 1  a  1  2
 2  a  2  3

$b
   V1 V2 V3
 3  b  3  4
 4  b  4  2

$c
   V1 V2 V3
 5  c  5  2

Ich möchte dies mit group_by (etwas wie group_by(df,V1)) emulieren, aber dies gibt einen, grouped_df zurück. Ich weiß, dass do in der Lage sein sollte, mir zu helfen, aber ich bin nicht sicher über die Verwendung (siehe auch link für eine Diskussion.)

Beachten Sie, dass Split jede Liste nach dem Namen des Faktors benennt, der zur Einrichtung dieser Gruppe verwendet wurde - dies ist eine gewünschte Funktion (letztendlich Bonus-Kudos für eine Möglichkeit, diese Namen aus der Liste der DFS zu extrahieren).

19
MartinT

Vergleicht man die Basislösungen, plyr und dplyr, scheint die Basislösung viel schneller zu sein!

library(plyr)
library(dplyr)   

df <- data_frame(Group1=rep(LETTERS, each=1000),
             Group2=rep(rep(1:10, each=100),26), 
             Value=rnorm(26*1000))

microbenchmark(Base=df %>%
             split(list(.$Group2, .$Group1)),
           dplyr=df %>% 
             group_by(Group1, Group2) %>% 
             do(data = (.)) %>% 
             select(data) %>% 
             lapply(function(x) {(x)}) %>% .[[1]],
           plyr=dlply(df, c("Group1", "Group2"), as.tbl),
           times=50) 

Gibt:

Unit: milliseconds
  expr      min        lq      mean    median        uq       max neval
  Base 12.82725  13.38087  16.21106  14.58810  17.14028  41.67266    50
  dplyr 25.59038 26.66425  29.40503  27.37226  28.85828  77.16062   50
  plyr 99.52911  102.76313 110.18234 106.82786 112.69298 140.97568    50
14
Matifou

Um an Dplyr festzuhalten, können Sie auch plyr anstelle von split verwenden:

library(plyr)

dlply(df, "V1", identity)
#$a
#  V1 V2 V3
#1  a  1  2
#2  a  2  3

#$b
#  V1 V2 V3
#1  b  3  4
#2  b  4  2

#$c
#  V1 V2 V3
#1  c  5  2
13
Colonel Beauvel

Sie können eine Liste von Datenrahmen von group_by mit do abrufen, solange Sie die neue Spalte benennen, in der die Datenrahmen gespeichert werden, und diese Spalte dann in lapply leiten.

listDf = df %>% group_by(V1) %>% do(vals=data.frame(.)) %>% select(vals) %>% lapply(function(x) {(x)})
listDf[[1]]
#[[1]]
#  V1 V2 V3
#1  a  1  2
#2  a  2  3

#[[2]]
#  V1 V2 V3
#1  b  3  4
#2  b  4  2

#[[3]]
#  V1 V2 V3
#1  c  5  2
8
COrtega

Seit dplyr 0.5.0.9000 wird die kürzeste Lösung, die group_by() verwendet, wahrscheinlich do mit einer pull folgen:

df %>% group_by(V1) %>% do(data=(.)) %>% pull(data)

Beachten Sie, dass im Gegensatz zu split die resultierenden Listenelemente nicht benannt werden. Wenn dies gewünscht ist, dann möchten Sie wahrscheinlich so etwas wie

df %>% group_by(V1) %>% do(data = (.)) %>% with( set_names(data, V1) )

Um ein wenig zu redigieren, stimme ich den Leuten zu, die sagen, dass split() die bessere Option ist. Ich persönlich fand es immer ärgerlich, dass ich den Namen des Datenrahmens zweimal eingeben muss (z. B. split( potentiallylongname, potentiallylongname$V1 )), aber das Problem lässt sich leicht mit der Pipe umgehen:

df %>% split( .$V1 )
3
Artem Sokolov

group_split in dplyr 0.8:

Der Release-Kandidat 0.8 von dplyr hat group_split als experimentelle Funktion implementiert: https://dplyr.tidyverse.org/reference/group_split.html

Es teilt einen Datenrahmen nach Gruppen auf und gibt eine Liste von Datenrahmen zurück. Jeder dieser Datenrahmen ist eine Teilmenge der ursprünglichen Datenrahmen, die durch Kategorien der Aufteilungsvariablen definiert werden. 

Zum Beispiel. Teilen Sie den Datensatz iris durch die Variable Species auf und berechnen Sie die Zusammenfassungen jedes einzelnen Sub-Datasets:

> iris %>% 
+     group_split(Species) %>% 
+     map(summary)
[[1]]
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.300   Min.   :2.300   Min.   :1.000   Min.   :0.100   setosa    :50  
 1st Qu.:4.800   1st Qu.:3.200   1st Qu.:1.400   1st Qu.:0.200   versicolor: 0  
 Median :5.000   Median :3.400   Median :1.500   Median :0.200   virginica : 0  
 Mean   :5.006   Mean   :3.428   Mean   :1.462   Mean   :0.246                  
 3rd Qu.:5.200   3rd Qu.:3.675   3rd Qu.:1.575   3rd Qu.:0.300                  
 Max.   :5.800   Max.   :4.400   Max.   :1.900   Max.   :0.600                  

[[2]]
  Sepal.Length    Sepal.Width     Petal.Length   Petal.Width          Species  
 Min.   :4.900   Min.   :2.000   Min.   :3.00   Min.   :1.000   setosa    : 0  
 1st Qu.:5.600   1st Qu.:2.525   1st Qu.:4.00   1st Qu.:1.200   versicolor:50  
 Median :5.900   Median :2.800   Median :4.35   Median :1.300   virginica : 0  
 Mean   :5.936   Mean   :2.770   Mean   :4.26   Mean   :1.326                  
 3rd Qu.:6.300   3rd Qu.:3.000   3rd Qu.:4.60   3rd Qu.:1.500                  
 Max.   :7.000   Max.   :3.400   Max.   :5.10   Max.   :1.800                  

[[3]]
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.900   Min.   :2.200   Min.   :4.500   Min.   :1.400   setosa    : 0  
 1st Qu.:6.225   1st Qu.:2.800   1st Qu.:5.100   1st Qu.:1.800   versicolor: 0  
 Median :6.500   Median :3.000   Median :5.550   Median :2.000   virginica :50  
 Mean   :6.588   Mean   :2.974   Mean   :5.552   Mean   :2.026                  
 3rd Qu.:6.900   3rd Qu.:3.175   3rd Qu.:5.875   3rd Qu.:2.300                  
 Max.   :7.900   Max.   :3.800   Max.   :6.900   Max.   :2.500     

Es ist auch sehr hilfreich beim Debuggen von Berechnungen für verschachtelte Datenframes, da dies eine schnelle Möglichkeit ist, die Berechnungen "verschachtelter" Datenframes zu "sehen". Es ist noch nicht auf cran, aber Sie können es mit devtools installieren:

devtools::install_github("tidyverse/[email protected]_0.8.0")
0
Rasmus Larsen

Seit dplyr 0.8 können Sie group_split verwenden.

library(dplyr)
df = as.data.frame(cbind(c("a","a","b","b","c"),c(1,2,3,4,5), c(2,3,4,2,2)))
df %>% group_by(V1) %>% group_split()
#> [[1]]
#> # A tibble: 2 x 3
#>   V1    V2    V3   
#>   <fct> <fct> <fct>
#> 1 a     1     2    
#> 2 a     2     3    
#> 
#> [[2]]
#> # A tibble: 2 x 3
#>   V1    V2    V3   
#>   <fct> <fct> <fct>
#> 1 b     3     4    
#> 2 b     4     2    
#> 
#> [[3]]
#> # A tibble: 1 x 3
#>   V1    V2    V3   
#>   <fct> <fct> <fct>
#> 1 c     5     2
0