2015-05-08 7 views
10

Ich arbeite mit der folgenden Art von Daten-SetPause Liste in Zeilen während Identifikatoren in r Erhaltung

names<-c("Aname","Aname","Bname","Cname","Cname") 
    list <- list(c('a, b','b, r','c, g'), c('d,g','e,j'), 
    c('d, h','s, q','f,q'), c('d,r ','s, z'),c('d, r','d, r')) 
    data<-cbind(names, list) 

Und will jedes Element einer Liste zu durchbrechen und dann bindet sie mit dem „Namen“ Variable. Also der Datensatz Ich versuche, so zu produzieren aussehen würde:

Column 1 Column 2 
Aname  a 
Aname  b 
Aname  b 
Aname  r 
Aname  c 

Es gab viele Diskussionen gewesen, wie eine Liste zu einem data.frame konvertieren, aber ich bin zu kämpfen irgendwelche Ratschläge zu finden, wie zum tun Sie dies "innerhalb" eines Datenrahmens, wo ich Bezeichner in derselben Zeile wie die Liste (in diesem Fall Namen) beibehalten möchte. Danke vielmals!

+1

Bitte nichts 'names' nennen oder' list'; Dies sind bereits die Namen häufig verwendeter Funktionen. – Frank

+0

@Frank, aber so sind 'Daten' und' df' und ich sehe nicht viele Leute sich darüber beschweren. Die Wahrheit ist, dass in den meisten Fällen nur die Lesbarkeit beeinträchtigt ist, nicht die Funktionalität .... – A5C1D2H2I1M1N2O1R2T1

Antwort

2

So geht's mit dplyr/tidyr. Die Idee ist, jedes Element von list zu einer Liste selbst (aus einem Zeichenvektor, der es derzeit ist) zu konvertieren und rief dann die sehr nützlich unnest Funktion

library(dplyr) 
library(tidyr) 
data.frame(data) %>% 
    unnest(list) %>% 
    mutate(list = strsplit(list, ",")) %>% 
    unnest(list) 
# names list 
#1 Aname a 
#2 Aname b 
#3 Aname b 
#4 Aname r 
#5 Aname c 
#6 Aname g 
#7 Aname d 
#8 Aname g 
#9 Aname e 
#10 Aname j 
#11 Bname d 
#12 Bname h 
#13 Bname s 
#14 Bname q 
#15 Bname f 
#16 Bname q 
#17 Cname d 
#18 Cname r 
#19 Cname s 
#20 Cname z 
#21 Cname d 
#22 Cname r 
#23 Cname d 
#24 Cname r 

(Um von zusätzlichen Leerzeichen entfernen, wenn nötig, Sie können %>% mutate(list = gsub(" ", "", list)) an die Befehlskette anhängen.)

+0

Vielen Dank. Wenn ich das auf meinen echten Daten ausführe, erhalte ich den folgenden Fehler: "Fehler: Spalten sind nicht alle gleich lang" irgendwelche Ideen? Vielen Dank –

+0

Ich kann mich nicht daran erinnern, diesen Fehler gesehen zu haben, ich stelle mir vor, dass er von 'unnest' geworfen wird. Könnten Sie die Befehle entketten und nacheinander ausführen und mir mitteilen, in welchem ​​Stadium dieser Fehler auftritt? – konvas

5

Hier ist eine mögliche Basis R Lösung

myFunc <- function(x) unlist(strsplit(unlist(x), ", | |,")) 

data.frame(Col1 = rep(names, sapply(list, function(x) length(myFunc(x)))), 
      Col2 = myFunc(list)) 

#  Col1 Col2 
# 1 Aname a 
# 2 Aname b 
# 3 Aname b 
# 4 Aname r 
# 5 Aname c 
# 6 Aname g 
# 7 Aname d 
# 8 Aname g 
# 9 Aname e 
# 10 Aname j 
# 11 Bname d 
# 12 Bname h 
# 13 Bname s 
# 14 Bname q 
# 15 Bname f 
# 16 Bname q 
# 17 Cname d 
# 18 Cname r 
# 19 Cname s 
# 20 Cname z 
# 21 Cname d 
# 22 Cname r 
# 23 Cname d 
# 24 Cname r 
+0

Vielen Dank. Ich bekomme und "Argumente implizieren abweichende Anzahl von Zeilen" Fehler mit meinen "echten" Daten - ich denke, es kann mit der Art und Weise in Zusammenhang stehen, wie die Liste indiziert wird.In der Datenansicht sieht eine Zeile wie folgt aus: list (c ("unser", "booth"), c ("booth", "at"), c ("at", "freiwillig"), c ("freiwillig", "Tag")). Irgendwelche Ideen? Entschuldigung, ich bin ein bisschen wie ein Noob. –

+0

Bearbeitet. Versuche es jetzt. –

+0

Vielen Dank, David. Leider bekomme ich immer noch einen Fehler: Fehler in strsplit (unlist (x), ", | |,"): Nicht-Zeichen-Argument. Ich muss irgendeine Art von seltsamen Daten in einer meiner Listen haben. Dies sind Bigramme, die aus einem Zeichenvektor erstellt wurden ... sie sollten alle Zeichen sein. Könnte es sich auf eine andere Art von Interpunktionszeichen beziehen? –

6

Sie melt

01 verwenden könnte
library(reshape2) 
melt(lapply(setNames(list, names), function(x) 
         unlist(strsplit(x, ', | |,')))) 
+0

@Tim es funktioniert, weil "|" bedeutet "oder". Aber was wäre, wenn der letzte Eintrag "d, r" wäre? Dies würde zusätzliche unerwünschte Einträge erzeugen, deren Wert ein einzelnes Leerzeichen ist, richtig? – konvas

+0

Oh, ich habe gerade festgestellt, dass dies die gleiche ist wie die Antwort, die ich gerade hinzugefügt habe. Verwenden Sie bei Basis R 'stack' anstelle von' melt' für das gleiche Ergebnis (mit unterschiedlichen Spaltennamen). – Frank

+0

@konvas Ich habe nicht alle möglichen Fälle versucht. Danke – akrun

4

Ein weiterer Ansatz mit splitstackshape - seine cSplit Funktionsstreifen Leerzeichen neben dem Trennzeichen standardmäßig.

library(splitstackshape) 
lengths <- sapply(data[, 2], length) 
nameslist <- unlist(rep(data[, 1], lengths)) 
df1 <- data.frame(names = nameslist, chars = unlist(data[, 2])) 
cSplit(df1, "chars", sep = ",", direction = "long") 

Oder per Ananda Kommentar einfach wie folgt:

cSplit(data.table(names = data[, "names"], list = sapply(data[, "list"], toString)), 
"list", ",", "long") 

Ergebnis:

names chars 
1: Aname  a 
2: Aname  b 
3: Aname  b 
4: Aname  r 
5: Aname  c 
6: Aname  g 
7: Aname  d 
8: Aname  g 
9: Aname  e 
10: Aname  j 
11: Bname  d 
12: Bname  h 
13: Bname  s 
14: Bname  q 
15: Bname  f 
16: Bname  q 
17: Cname  d 
18: Cname  r 
19: Cname  s 
20: Cname  z 
21: Cname  d 
22: Cname  r 
23: Cname  d 
24: Cname  r 

Wenn Sie das Ergebnis als data.table nicht wollen, können Sie die letzte Zeile in as.data.frame() wickeln können .

+2

Ich würde persönlich' cSplit machen (data.table (names = data [, "names"], list = sapply (data [, "list"], toString)), "list", ",", "long") ', aber +1 – A5C1D2H2I1M1N2O1R2T1

+0

@Ananda das ist eine elegante Lösung, kurz und einfach zu folgen. Ich habe es der Antwort hinzugefügt, danke. –

+1

Eine weitere Variante: 'cSplit (stack (setNames (Daten [, 2], Daten [, 1]))," Werte ",", "," lang ")'. – A5C1D2H2I1M1N2O1R2T1

2

Das OP knotet zwei Fragen zusammen.

Die Antwort auf die erste ist, die Daten zu bereinigen. Zum Beispiel das Kopieren @ DavidArenburg der Funktion:

myFunc <- function(x) unlist(strsplit(unlist(x), ", | |,")) 
clean <- sapply(list, myFunc) 

und der zweite Schritt ist zu stapeln:

stack(setNames(clean,names)) 
+1

Leider weist dies jeden String innerhalb der Liste zu, aber nicht jedes Element in der Liste). Danke für die Hilfe! –

+1

@ChrisBail Ich kenne den Unterschied zwischen diesen beiden Dingen nicht. Keine Notwendigkeit zu erklären, ob eine der anderen Antworten für Sie funktioniert; Sie können einfach auf das Häkchen bei dieser Antwort klicken. Wenn keiner von ihnen funktioniert, müssen Sie möglicherweise Ihre Frage bearbeiten, um die Beispieldaten zu verdeutlichen und/oder zu ändern. – Frank

+1

Sorry, ich lerne immer noch die Seile! –