2016-04-20 6 views
1

Ich versuche, eine Spalte "data.frame" automatisch in mehrere Spalten zu konvertieren.Python-ähnliche Liste in verschachtelte Vektoren konvertieren

Hier ist, was die df wie folgt aussieht:

library(dplyr) 
foo <- data_frame(ID = c(1,2), 
        Val = c("A", "B"), 
        Geom = c("[{X11,Y11,Z11}, {X12,Y12,Z12}, {X13,Y13,Z13}]", "[{X21,Y21,Z21},{X22,Y22,Z22},{X23,Y23,Z23}]")) 

Hier ist, was ich möchte aussehen:

bar <- data_frame(ID = c(1,1,1,2,2,2), 
        Val=c("A", "A", "A", "B", "B", "B"), 
        Geom1 = c("X11", "X12", "X13", "X21", "X22", "X23"), 
        Geom2 = c("Y11", "Y12", "Y13", "Y21", "Y22", "Y23"), 
        Geom3 = c("Z11", "Z12", "Z13", "Z21", "Z22", "Z23")) 

Der Workflow ich für eine solche Transformation besteht aus 2 Teilen betrachten:

1 - Konvertieren Geom in eine R-Struktur, wie:

list(c("X11","Y11","Z11"), c(...), ...) 

2 - Verwenden Sie tidyr::unnest() oder tidyr::separate() solche Liste in Spalten teilen

Ich glaube, ich den zweiten Teil behandeln kann, kann aber nicht den guten Zeiger zum ersten finden. Ich könnte diese Spalte in einen csv schreiben und automatisch danach lesen, aber wenn ich bedenke, dass mein data.frame ein glänzendes reaktives Objekt sein wird, würde das viel Schreiben/Lesen bedeuten.

Ich habe versucht, fromJSON() (jsonlite, rjson und RJSONIO) zu verwenden, aber da dies keine gültige json-Zeichenfolge ist, wird es nicht analysiert.

+0

@wildintellect im IRC sagte mir, dass fromJSON funktioniert, wenn Sie {} mit []. Ich werde diese verschiedenen Lösungen trotzdem testen und diese vergleichen, wobei ich Pipes über Temp-Variablen bevorzuge :) – RobinCura

+1

Wenn Sie Pipes mögen, können Sie die Antwort des Colonels wie 'setDT (foo) [, Geom%>% gsub (pattern = '\\ [{|} \\]', ersatz = '', perl = WAHR)%>% strsplit (split = '}, * {', perl = T),. (ID, Val)] oder ähnlich in dplyrisch. – Frank

+0

Hat es ohne splitstackshape wie folgt getan: 'setDT (foo) [, strsplit (gsub ('\\ [{|} \\]', '', Geom, perl = T), '}, * {', perl = T),.(ID, Val)]%>% getrennt (V1, in = c ("X", "Y", "Z"), konvertieren = TRUE, sep = ",")%>% mutieren (UID = id (liste (ID, Val))) ' – RobinCura

Antwort

4

eine Lösung mit data.table/splitstackshape:

library(data.table) 
library(splitstackshape) 

dt = setDT(foo)[,strsplit(gsub('\\[{|}\\]','', Geom, perl=T), '}, *{', perl=T), .(ID, Val)] 

cSplit(dt, 'V1') 
# ID Val V1_1 V1_2 V1_3 
#1: 1 A X11 Y11 Z11 
#2: 1 A X12 Y12 Z12 
#3: 1 A X13 Y13 Z13 
#4: 2 B X21 Y21 Z21 
#5: 2 B X22 Y22 Z22 
#6: 2 B X23 Y23 Z23 
+1

oder' tstrsplit' verwenden: 'foo [, tstrsplit (strsplit (...) [[1]],', '),. (ID, Val)]' – eddi

2

ist hier ein Verfahren unter Verwendung von Basis R:

# vector to work with 
geom <- c("[{X11,Y11,Z11}, {X12,Y12,Z12}, {X13,Y13,Z13}]", "[{X21,Y21,Z21},{X22,Y22,Z22},{X23,Y23,Z23}]") 
# remove extraneous characters and split into list using "}," 
geom <- strsplit(gsub("[]{ []", "", Geom), split="},") 
# remove two "}"s 
geom <- sapply(geom, function(i) gsub("}", "", i)) 
# make a list of elements 
geom <- strsplit(geom, split=",") 

# construct the variables 
geomData <- data.frame(t(sapply(geom, function(i) sapply(1:3, function(row) c(i[row]))))) 
# give names to data frame 
names(geomData) <- c("Geom1", "Geom2", "Geom3") 

# final data.frame 
fooNew <- cbind(foo[, 1:2], geomData) 
1

1) dplyr den Datenrahmen in Zeilen Diese Splits und für jede solche Zeile verwendet gsub, um jedes Triple auf eine separate Zeile aufzuteilen und , um Geom weiter zu analysieren. Dann behebt es die Spaltennamen und macht eine ungroup. (Die setNames Linie weggelassen werden könnte, wenn V1, V2 und V3 sind OK statt Geom1, Geom2 und Geom3.)

library(dplyr) 

foo %>% 
    group_by(ID, Val) %>% 
    do(read.table(text=gsub("^..|..$|}, *{", "\n", .$Geom, perl=T), sep=",", as.is=T)) %>% 
    setNames(sub("^V(\\d+)", "Geom\\1", colnames(.))) %>% 
    ungroup() 

geben:

Source: local data frame [6 x 5] 

    ID Val Geom1 Geom2 Geom3 
    (dbl) (chr) (chr) (chr) (chr) 
1  1  A X11 Y11 Z11 
2  1  A X12 Y12 Z12 
3  1  A X13 Y13 Z13 
4  2  B X21 Y21 Z21 
5  2  B X22 Y22 Z22 
6  2  B X23 Y23 Z23 

2) Keine Pakete Dies verwendet die gleiche Annäherung, aber ohne irgendwelche Pakete. Die letzte Codezeile könnte weggelassen werden, wenn V1, V2, V3 OK statt Geom1, Geom2 und Geom3 sind.

bar <- do.call("rbind", by(foo, foo$ID, function(x) 
    cbind(x[1:2], read.table(text = gsub("^..|..$|}, *{", "\n", x$Geom, perl=T), sep=",")))) 
names(bar) <- sub("^V(\\d+)", "Geom\\1", names(bar)) 

geben:

> bar 
    ID Val Geom1 Geom2 Geom3 
1.1 1 A X11 Y11 Z11 
1.2 1 A X12 Y12 Z12 
1.3 1 A X13 Y13 Z13 
2.1 2 B X21 Y21 Z21 
2.2 2 B X22 Y22 Z22 
2.3 2 B X23 Y23 Z23