2012-04-15 12 views
7

Tengo un conjunto de marcos de datos con los mismos encabezados de columna, excepto que algunos de los nombres de columna están en mayúscula y algunos están en minúscula. Quiero convertir todos los nombres de columna en minúsculas para poder crear un gran marco de datos de todo.¿Cómo configuro los nombres de las columnas en minúsculas para múltiples dataframes?

Parece que no puedo obtener colnames() para trabajar en ningún bucle o aplicar para escribir. 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) 

me sale el siguiente error:

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

¿Cómo cambio todos mis tramas de datos que tienen nombres de columna minúsculas?

Respuesta

8

El siguiente debería funcionar:

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

Problemas como éste generalmente se derivan del hecho de que no ha colocado todas sus tramas de datos en una única estructura de datos, y luego se ven obligados a usar algo torpe, como get.

No es que en mi código, yo uso lapply y get para realmente crear una lista única de tramas de datos primeros, y luego alterar sus COLNAMES.

También debe tener en cuenta que su función de lowcols es bastante diferente a R-like. Por lo general, las funciones R no se llaman de tal forma que no devuelvan nada, sino que tengan efectos secundarios. Si intenta escribir funciones de esa manera (lo cual es posible), probablemente le dificultará la vida y tendrá problemas de alcance. Tenga en cuenta que en mi segundo lapply devuelvo explícitamente el marco de datos modificado.

+0

¿Por qué no se me ocurrió hacer una lista de los marcos de datos? Por supuesto, esa es una mejor solución. Aceptaré la respuesta tan pronto como tenga la oportunidad de probarla. –

+0

Eso funciona perfectamente, y luego tener los marcos de datos como una lista, obtener todos los marcos de datos separados en un gran df era tan simple como 'data <-dbl (dfList, rbind.fill)' Gracias y estoy muy agradecido de la comunidad constructiva y útil aquí. –

+0

¿Es 'lapply (dfs, get)' realmente necesario? Simplemente el suministro de la lista de marcos de datos no sería suficiente? –

4

@ La respuesta de joran se superpone fuertemente a la mía, tanto en el estilo como en el mensaje "probablemente quieras hacerlo de otra manera". Sin embargo, en el espíritu de "dale a un hombre un pez y lo alimentas por un día; dale un palo afilado, y él puede meterse en el ojo" ...

Aquí hay una función que hace lo que quieres en la forma en que (se cree) que desee hacerlo:

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 
} 

Éstos son dos funciones alternativas que los nombres de columna en minúsculas y devolver el resultado:

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

incluyo plyr::rename aquí para completar, aunque en este caso, en realidad es más problemas de lo que vale.

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 por dar a un hombre una vara filosa. –

+0

Gracias por el código claro que me muestra cómo haría lo que pensé que quería hacer. No entiendo qué está haciendo 'sys.frame (-2)' en 'assign()', pero eso es probablemente porque no entiendo asignar todo muy bien. –

1

Esto no responde directamente a su pregunta, pero puede resolver el problema que está tratando de resolver; Puede combinar data.frames por diferentes nombres a través de algo como:

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 más de 2 dfs para tratar, fusionar no es la respuesta, pero gracias por los consejos. Estoy seguro de que serán útiles en el futuro. –

+0

@WilliamGunn: Usted dijo: "Quiero convertir todos los nombres de las columnas a minúsculas para poder fusionarlas". Solo estaba señalando que no tiene que cambiar los nombres de las columnas para fusionar los data.frames. Tal vez usaste fusion cuando querías append/rbind? –

+0

¡Entendí lo que estabas respondiendo y gracias! Era confuso cómo usé la palabra fusionar, pero no me refirió específicamente al uso de 'merge()', que solo funciona en pares de dataframes. Cambiaré eso. –

Cuestiones relacionadas