2011-11-01 12 views
5

Sto cercando di unire un numero di dataframes usando rbind. Se chiamo directy rbind non c'è problema:perdita di frame quando si utilizza do.call

> test <- rbind(x) 
> is.data.frame(x) 
[1] TRUE 

tuttavia, se uso do.call corro in un problema in cui sono compressi miei colonne di caratteri e il dataframe vengono convertiti in una matrice.

>test <- do.call("rbind", x) 
> is.data.frame(test) 
[1] FALSE 

Come per la documentazione rbind? Ho provato add stringsAsFactors = FALSE ma nessun cambiamento nel comportamento. Le mie tabelle di dati sono qualcosa del tipo:

ID sequence descriptor 
1 aaacccttt g12 
2 actttgtgt e34 
3 tttgggctc b12 
4 ccgcgcgcg c12 
… …  ... 

e l'uscita rbind appare come questo, ma si presenta come segue, in cui la colonna di sequenza non è più un personaggio l'uscita do.call("rbind", x):

ID 363 426 91 
Sequence 98 353 100 
descriptor g12 b12 c12 

vorrei utilizzare do.call perché eseguo il ciclo di un set di frame di dati per consolidarli utilizzando uno script di seguito. Un'altra risposta utile potrebbe offrire una soluzione alternativa su come unire più dataframes mentre li si chiama in un ciclo.

stringsAsFactors = FALSE 
dfs <- as.list(ls(pattern="Data_")) 
for (i in 1:length(dfs)) { 
    x <- get(as.character(dfs[i])) 
    AllData <- do.call("rbind", x) 
    } 

dfs è la lista dei dataframes nel mio ambiente di lavoro e ho la dataframe reale utilizzando get

grazie.

risposta

4

Ci sono due diversi problemi che causano difficoltà.

  • stringsAsFactors

hai ragione di essere alla ricerca stringsAsFactors, ma semplicemente non hanno chiamato in modo del tutto al posto giusto.

Hai due opzioni. È possibile impostare nel vostro options, in questo modo:

options(stringsAsFactors=FALSE) 

O nel codice utilizzato per creare i data.table s:

a <- read.table(textConnection("ID sequence descriptor 
1 aaacccttt g12 
2 actttgtgt e34 
3 tttgggctc b12 
4 ccgcgcgcg c12"), 
header=T, stringsAsFactors=FALSE) 
  • args= argomento a do.call()

È Sono anche sulla strada giusta nel voler usare do.call() per questo. Ma, come sottolinea @Sacha, dfs deve essere un elenco di data.frame s, non un singolo data.frame (che è di per sé un elenco di vettori).

# Create list of two data.frames 
b <- a 
dfs <- list(a, b) 

# Or, if you start with a list of their names 
dfs <- list("a", "b") 
dfs <- lapply(dfs, get) 

# Check that this works 
do.call("rbind", dfs) 
# ID sequence descriptor 
# 1 1 aaacccttt  g12 
# 2 2 actttgtgt  e34 
# 3 3 tttgggctc  b12 
# 4 4 ccgcgcgcg  c12 
# 5 1 aaacccttt  g12 
# 6 2 actttgtgt  e34 
# 7 3 tttgggctc  b12 
# 8 4 ccgcgcgcg  c12 

Questo dovrebbe funzionare anche per voi, anche se si dispone di un solo data.frame, fintanto che è avvolto in un (lunghezza-1) list, in questo modo: dfs <- list(a)

+0

questa è una risposta fantastica. – zach

2

Utilizzando Josh' codice di esempio .Sono abbastanza sicuro che ciò che sta accadendo è questo:

Data: 
    x <- read.table(textConnection("ID sequence descriptor 
    1 aaacccttt g12 
    2 actttgtgt e34 
    3 tttgggctc b12 
    4 ccgcgcgcg c12"), 
    header=T, stringsAsFactors=FALSE) 

Prima questo:

rbind(x) 

non fa nulla in quanto non v'è un solo argomento. Cioè non c'è nulla da aggiungere al frame dei dati, quindi restituisce lo stesso dataframe. Poi:

do.call("rbind", x) 

Quello che succede qui è che rbind() si chiama con tutti gli argomenti nella lista x. Un frame di dati è un elenco con colonne come elementi. Pertanto, questo sarebbe lo stesso:

rbind(x$ID,x$sequence,x$descriptor) 

in modo da mettere insieme tre vettori per riga. Quindi, questo diventa la trasposizione di ciò che hai e dato che data.frames memorizza solo diversi tipi di vettori in senso orario, questo deve diventare una matrice di caratteri.

Penso che se x è un elenco di dataframes funziona correttamente. Non dovrebbe essere solo un frame di dati.

+0

grazie Sacha, penso che tu abbia perfettamente descritto cosa sta succedendo – zach

1

Penso che quello che cerchi possa essere fatto senza un loop usando Reduce. È una funzione di ordine superiore, che successivamente applica una funzione a due elementi da un elenco.

dfs <- as.list(ls(pattern="Data_")) 
Reduce('rbind', dfs) 
+0

grazie Ramnath, tuttavia quando provo questo approccio non restituisco un set di dati, ma piuttosto una matrice di caratteri. Non sapevo di Ridurre, quindi sicuramente lo esaminerò. – zach

Problemi correlati