2015-05-14 12 views
14

Il mio riquadro dati contiene l'output di un sondaggio con un tipo di domanda multipla selezionato. Alcune celle hanno più valori.Colonna di lista degli zoccoli nel frame di dati con colonna ID

df <- data.frame(a=1:3,b=I(list(1,1:2,1:3))) 
df 
    a  b 
1 1  1 
2 2 1, 2 
3 3 1, 2, 3 

vorrei appiattire la lista per ottenere il seguente output:

df 
    a  b 
1 1  1 
2 2  1 
3 2  2 
4 3  1 
5 3  2 
6 3  3 

dovrebbe essere facile, ma in qualche modo non riesco a trovare i termini di ricerca. Grazie.

risposta

16

si può semplicemente utilizzare unnest da "tidyr":

library(tidyr) 
unnest(df, b) 
# a b 
# 1 1 1 
# 2 2 1 
# 3 2 2 
# 4 3 1 
# 5 3 2 
# 6 3 3 
+0

grazie! perfetto, avevo guardato Tidyr ma non ho trovato questo caso particolare – mloudon

+0

L'OP ha detto che dovrebbe essere facile, e hai dimostrato che è davvero così facile! Bel lavoro! –

7

Utilizzando base R, una possibilità è stack dopo aver nominato i list elementi della colonna 'b' con quella degli elementi di 'a'. Possiamo usare setNames per cambiare i nomi.

stack(setNames(df$b, df$a)) 

o un'altra opzione sarebbe quella di utilizzare unstack di nominare automaticamente l'elemento elenco di 'b' con elementi 'a' e poi fare il stack per ottenere un'uscita data.frame.

stack(unstack(df, b~a)) 

Oppure si può usare una comoda funzione listCol_l da splitstackshape per convertire il list-data.frame.

library(splitstackshape) 
listCol_l(df, 'b') 
+2

Bel lavoro. Mi piace sempre vedere soluzioni base semplici ed eleganti. –

4

Ecco un modo, con data.table:

require(data.table) 
data.table(df)[,as.integer(unlist(b)),by=a] 

Se b viene memorizzato in modo coerente, as.integer può essere saltata. È possibile verificare con

unique(sapply(df$b,class)) 
# [1] "numeric" "integer" 
+3

'df $ b [1] <- lista (1L)' anche noi manuale e inpratico se l'OP ha molte di queste voci. Penso che qualcosa come 'data.table (df) [, as.integer (unlist (b)), da = a]' dovrebbe fare –

+0

@DavidArenburg Sì, o ingerire i dati in R "correttamente" (nel senso di memorizzando come numeri interi in primo piano). Passerò a ciò che hai scritto. – Frank

3

Ecco un'altra soluzione di base, molto meno elegante di qualsiasi altra soluzione pubblicata finora. Pubblicare per completezza, anche se personalmente consiglierei la soluzione di base di akrun.

with(df, cbind(a = rep(a, sapply(b, length)), b = do.call(c, b))) 

Questo costruisce la prima colonna come gli elementi di a, dove ognuno viene ripetuto in base alla lunghezza dell'elemento di elenco corrispondente dal b. La seconda colonna è b "appiattita" utilizzando do.call() con c().

Come indicato da Ananda Mahto in un commento, sapply(b, length) può essere sostituito con lengths(b) nella versione più recente di R (3.2, se non sbaglio).

+3

Nella versione più recente di R, puoi scambiare 'sapply (b, length)' con 'lengths (b)'. – A5C1D2H2I1M1N2O1R2T1

+0

@AnandaMahto: È fantastico, grazie per l'attenzione! –

+0

per recuperare un data.frame, è meglio usarlo: 'con (df, data.frame (a = rep (a, lengths (b)), b = unlist (b)))' – Jaap

Problemi correlati