2012-04-15 18 views
7

Ho un set di dataframe con le stesse intestazioni di colonna, tranne per il fatto che alcuni nomi di colonne sono in maiuscolo e altri in minuscolo. Voglio convertire tutti i nomi delle colonne in minuscolo in modo da poter creare un grande dataframe di tutto.Come si impostano i nomi delle colonne in lettere minuscole per più dataframes?

Non riesco a ottenere colnames() per funzionare in qualsiasi ciclo o applicare che scrivo. Con:

#create dfs 
df1<-data.frame("A" = 1:10, "B" = 2:11) 
df2<-data.frame("a" = 3:12, "b" = 4:13) 
df3<-data.frame("a" = 5:14, "b" = 6:15) 
#I have many more dfs in my actual data 

#make list of dfs, define lowercasing function, apply across df list 
dfs<-ls(pattern = "df") 
lowercols<-function(df){colnames(get(df))<-tolower(colnames(get(df)))} 
lapply(dfs, lowercols) 

ottengo il seguente errore:

Error in colnames(get(df)) <- tolower(colnames(get(df))) : 
    could not find function "get<-" 

Come faccio a cambiare tutti i miei dataframes di avere i nomi di colonna in minuscolo?

risposta

8

Il seguente dovrebbe funzionare:

dfList <- lapply(lapply(dfs,get),function(x) {colnames(x) <- tolower(colnames(x));x}) 

Problemi di questo genere derivano dal fatto che non hai messo tutti i frame di dati in un'unica struttura di dati, e quindi sono costretti ad utilizzare qualcosa di imbarazzante, come get.

Non che nel mio codice, io uso lapply e get per creare effettivamente un unico elenco di frame di dati primi, e quindi alterare le loro colnames.

Si dovrebbe anche essere consapevoli del fatto che la vostra funzione in lettere minuscole è piuttosto un-R come. Le funzioni R in genere non vengono chiamate in modo tale da non restituire nulla, ma hanno effetti collaterali. Se provi a scrivere le funzioni in questo modo (il che è possibile), probabilmente ti rendi difficile la vita e hai problemi di scoping. Si noti che nel mio secondo lapply restituisco esplicitamente il frame di dati modificato.

+0

Perché non mi è venuto in mente di creare un elenco dei frame di dati stessi? Certo che è una soluzione migliore. Accetterò la risposta non appena avrò la possibilità di provarlo. –

+0

Che funziona perfettamente, e quindi avere i frame di dati come una lista, ottenere tutti i frame di dati separati in un unico grande df era semplice come 'data <-ldply (dfList, rbind.fill)' Grazie e sono così riconoscente di la comunità costruttiva e utile qui. –

+0

È 'lapply (dfs, get)' veramente necessario? Fornire semplicemente la lista di data.frames non sarebbe sufficiente? –

4

@ la risposta di joran si sovrappone fortemente alla mia, sia nello stile che nel messaggio "probabilmente vuoi farlo in modo diverso". Tuttavia, nello spirito di "dare a un uomo un pesce e dargli da mangiare per un giorno, dargli un bastone affilato, e si può colpire negli occhi" ...

Ecco una funzione che fa quello che vuoi nel modo in cui (si pensa) che si desidera farlo:

dfnames <- ls(pattern = "df[0-9]+") ## avoid 'dfnames' itself 
lowercolnames <- function(df) { 
    x <- get(df) 
    colnames(x) <- tolower(colnames(x)) 
    ## normally I would use parent.frame(), but here we 
    ## have to go back TWO frames if this is used within lapply() 
    assign(df,x,sys.frame(-2)) 
    ## OR (maybe simpler) 
    ## assign(df,x,envir=.GlobalEnv) 

    NULL 
} 

qui ci sono due funzioni alternative che i nomi di colonna minuscole e restituiscono il risultato:

lowerCN2 <- function(x) { 
    colnames(x) <- tolower(colnames(x)) 
    x 
} 

includo plyr::rename per completezza, anche se in questo caso è in realtà più problemi di quanti ne valga la pena.

lowerCN3 <- function(x) { 
    plyr::rename(x,structure(tolower(colnames(x)), 
          names=colnames(x))) 
} 

dflist <- lapply(dfnames,get) 
dflist <- lapply(dflist,lowerCN2) 
dflist <- lapply(dflist,lowerCN3) 
+0

+1 per dare a un uomo un bastone affilato. –

+0

Grazie per il codice chiaro che mi mostra come farei ciò che pensavo di voler fare. Non capisco cosa stia facendo 'sys.frame (-2)' in 'assign()', ma probabilmente non capisco perché assegnare tutto così bene. –

1

Questo non risponde direttamente alla tua domanda, ma può risolvere il problema che stai cercando di risolvere; è possibile unire data.frames con nomi diversi tramite qualcosa del tipo:

df1 <- data.frame("A" = 1:10, "B" = 2:11, x=letters[1:10]) 
df2 <- data.frame("a" = 3:12, "b" = 4:13, y=LETTERS[1:10]) 
merge(df1, df2, by.x=c("A","B"), by.y=c("a","b"), all=TRUE) 
+0

Con più di 2 dfs da gestire, l'unione non è la risposta, ma grazie per i suggerimenti. Sono sicuro che torneranno utili in futuro. –

+0

@WilliamGunn: hai detto, "Voglio convertire tutti i nomi delle colonne in minuscolo in modo da poterli unire". Stavo solo sottolineando che non è necessario modificare i nomi delle colonne per unire i data.frames. Forse hai usato l'unione quando intendevi append/rbind? –

+0

Ho capito cosa stavi rispondendo e grazie! Stava confondendo il modo in cui usavo la parola unione, ma non intendevo specificamente usare 'merge()', che funziona solo su coppie di dataframes. Lo cambierò. –

Problemi correlati