2017-02-26 4 views
0

Ich würde gerne über Spalten in einem Datenrahmen und teilen Sie sie in die basierend auf einem Trennzeichen. Ich verwende tidyr::separate, was funktioniert, wenn ich eine Spalte gleichzeitig mache.Anwenden tidyr :: über mehrere Spalten trennen

Zum Beispiel:

df<- data.frame(a = c("5312,2020,1212"), b = c("345,982,284")) 

df <- separate(data = df, col = "a", 
         into = paste("a", c("col1", "col2", "col3"), 
             sep = "_"), sep = ",") 

Returns:

a_col1 a_col2 a_col3   b 
1 5312 2020 1212 345,982,284 

Wenn ich versuche, den gleichen Vorgang über jede Spalte von df R auszuführen gibt einen Fehler

Zum Beispiel habe ich diese verwendet für Schleife:

for(col in names(df)){ 
    df <- separate(data = df, col = col, 
into = paste(col, c("col1", "col2", "col3), 
sep = "_"), sep = ",") 
    } 

Ich hatte erwartet, die folgende Ausgabe zu erhalten:

a_col1 a_col2 a_col3 b_col1 b_col2 b_col3 
1 5312 2020 1212 345 982 284 

jedoch R gibt diese Fehler:

Error in if (!after) c(values, x) else if (after >= lengx) c(x, values) else c(x[1L:after], : 
    argument is of length zero 

Gibt es eine andere Art und Weise tidyr::separate über mehrere Spalten in einem Datenrahmen zu bewerben?

+0

'df%>% sammeln() %>% seperate_rows (Wert)%>% muate (key = paste0 (Schlüssel, '_col', 1: 3))%>% spread (Schlüssel, Wert) ', aber das ist wirklich nicht einfacher als zweimal 'separate' aufzurufen. – alistaire

+0

... oder Sie können Ihr Original mit der SE 'seperate_' reparieren, dh' für (Name in Namen (df)) df <- seperate_ (df, name, in = paste0 (Name, '_col', 1: 3))) ', aber dieser Stil macht mich sehr unruhig. – alistaire

Antwort

1

Sie könnten einen benutzerdefinierten separate_() Anruf in Reduce() eingeben.

sep <- function(...) { 
    dots <- list(...) 
    n <- stringr::str_count(dots[[1]][[dots[[2]]]], "\\d+") 
    separate_(..., into = sprintf("%s_col%d", dots[[2]], 1:n)) 
} 

df %>% Reduce(f = sep, x = c("a", "b")) 
# a_col_1 a_col_2 a_col_3 b_col_1 b_col_2 b_col_3 
# 1 5312 2020 1212  345  982  284 

Andernfalls cSplit wird es auch tun.

splitstackshape::cSplit(df, names(df)) 
#  a_1 a_2 a_3 b_1 b_2 b_3 
# 1: 5312 2020 1212 345 982 284 
+0

'splatstapshape :: cSplit' ist nützlich.Allerdings ist die 'sep'-Funktion ein wenig verwirrend, sie funktioniert für gegebenes' df', aber wenn sie auf einen größeren und anderen Datenrahmen skaliert, schlägt sie fehl, was Sie wahrscheinlich schon wissen. – spies006

0

Ich hatte die gleiche Anfrage (Lern tidyverse), so durch so gearbeitet. N.B. dass ich eine Lösung wollte, die nicht zusammenbricht, also nicht darauf angewiesen ist, colnames zu kennen.

library(tidyverse) 

Erstellen Sie Ihre Eingabe:

dft <- as_tibble(data.frame(a = c("5312,2020,1212"), b = c("345,982,284"))) 
df <- as.data.frame(dft) 

eine leere tibble erstellen Ausgabe zu sammeln:

dft0 <- read_csv("a\na") 
dft0 <- dft0[,-1] 
dft00 <- dft0 

Geben Länge der Elemente getrennt werden (könnte in-Schleife durchgeführt werden, aber wir wissen von dft); N.B. wenn Sie einen besseren Weg, um Namen haben, verwenden Sie das:

leng <- 3 

For-Schleife Version:

for(x in 1:dim(df)[2]){ 
     dataCol <- dft[,x] 
     newCols <- paste(colnames(dataCol)[1], paste("col", 1:leng, sep="") , sep="_") 

     dft0 <- cbind(dft0, 
        separate(data = dataCol, 
          col = colnames(dataCol)[1], 
          into = newCols, 
          sep = ","))} 

Die chaotisch sapply Version:

sapp <- sapply(colnames(df),function(ff){ 
          separate(as_tibble(df[,ff]), 
            "value", 
            letters[1:leng], 
            sep=",")}) 

dft00 <- as_tibble(do.call(cbind, sapp)) 

colnames(dft00) <- as.vector(sapply(colnames(sapp), 
          function(sa){ 
             paste(sa, 
              rownames(sapp), 
              sep="_") 
             })) 
Verwandte Themen