2016-08-09 15 views
1

Ich habe ziemlich unordentliche Daten nach Kategorie, wo manchmal mehrere Kategorien in einem einzelnen Feld sind. Nach dem Aufteilen des Multi-Kategorie-Eintrags möchte ich jeder Kategorie in einem Kategorieeintrag den gleichen Wert zuweisen. Wenn beispielsweise die DatenWie effizient 1 Datenrahmen spalten, um einen neuen Datenrahmen zu erstellen, der jedem Teil der Kategoriespalte den gleichen Wert zuweist

cat <- c("A,B,C", "B", "B,C", "A,E") 
val <- c(300, 350, 400, 450) 
mydf <- data.frame(cat, val, stringsAsFactors = FALSE) 

     cat val 
     A,B,C 300 
      B 350 
      B,C 400 
      A,E 450 

aus der ersten Reihe ist, ich brauche 300 für jede Kategorie A zugeordnet werden, B & C, dann aus der zweiten Reihe 350 und B zugeordnet sind, 400 zu jedem B zugeordnet, und C aus der dritten Reihe und dann 450 A und E in der vierten Reihe zugeordnet.

Ich kam mit einer sehr kludy-y for-Schleife, um dies zu erreichen, aber ich weiß, dass dies nicht speicher-effizient ist, weil es rbind auf einem vorhandenen Datenrahmen verwendet.

resultsdf <- data.frame(temp_cats = character(0), 
      temp_vals = numeric(0), stringsAsFactors = FALSE) 

for(i in 1:nrow(mydf)){ 
    temp_cats <- stringr::str_split(mydf$cat[i], ",")[[1]] 
    temp_vals <- rep(val[i], length(temp_cats)) 
    temp_df <- data.frame(temp_cats, temp_vals, stringsAsFactors = FALSE) 
    resultsdf <- rbind(resultsdf, temp_df) 
} 

gerade gespannt, ob jemand eine elegantere R-Syntax Weg, dies zu erreichen mit

enden hat
temp_cats temp_vals 
1   A  300 
2   B  300 
3   C  300 
4   B  350 
5   B  400 
6   C  400 
7   A  450 
8   E  450 

Antwort

3

1) Stapel/entstapeln Verwenden strsplit die Saiten zu spalten und dann Entstapeln und stapeln Sie es, um die lange Form s erforderlich zu bekommen. Schließlich beheben Sie die Namen und machen temp_vals numerische seit unstack gezwungen, sie zu Charakter. Keine Pakete werden verwendet.

s <- stack(unstack(transform(mydf, cat = strsplit(cat, ",")))) 
with(s, data.frame(temp_cats = values, temp_vals = as.numeric(as.character(ind)))) 

2) dplyr/tidyr Ein weiterer Ansatz ist unnest im tidyr Paket zu verwenden:

library(dplyr) 
library(tidyr) 

mydf %>% 
    mutate(cat = strsplit(cat, ",")) %>% 
    unnest() %>% 
    transmute(temp_cat = cat, temp_vals = val) 

2a) Mit tidyr 5.0 oder später könnte dies sogar kürzer gemacht werden (wie spitze out von @aosmith in den Kommentaren). separate_rows verwendet unnest intern.

mydf %>% 
    separate_rows(cat) %>% 
    transmute(temp_cat = cat, temp_vals = val) 
+3

Sie auch 'verwenden könnten anstelle der' mutate'/'unnest' Combo separate_rows'. – aosmith

+0

Vielen Dank, ich wusste nicht, dass es in tidyr amnest ist, ich benutze immer noch hauptsächlich reshape2. Sehr hilfreich! – Sharon

1

Wir verwenden cSplit von splitstackshape

library(splitstackshape) 
setnames(cSplit(mydf, "cat", ",", "long"), c("temp_cats", "temp_vals"))[] 
# temp_cats temp_vals 
#1:   A  300 
#2:   B  300 
#3:   C  300 
#4:   B  350 
#5:   B  400 
#6:   C  400 
#7:   A  450 
#8:   E  450 
+1

War nicht vertraut mit diesem Paket, danke. – Sharon