如何为多个数据帧将列名设置为小写?

时间:2012-04-15 22:09:16

标签: r apply

我有一组具有相同列标题的数据框,除了一些列名称是大写的,一些是小写的。我想将所有列名称转换为小写,以便我可以创建一个大的数据帧。

我似乎无法让colnames()在任何循环中工作或应用我写。 用:

#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)

我收到以下错误:

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

如何将所有数据框更改为小写列名?

3 个答案:

答案 0 :(得分:8)

以下内容应该有效:

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

这样的问题通常源于你没有将所有数据框放在单个数据结构中,然后被迫使用尴尬的东西,如get

不是在我的代码中,我使用lapplyget来实际创建单个数据框列表 first ,然后更改其代码名称。

你还应该知道你的lowercols功能相当不喜欢。 R函数通常不会以不返回任何内容的方式调用,但会产生副作用。如果你试图以这种方式编写函数(这是可能的),你可能会让你的生活变得困难并且存在范围问题。请注意,在我的第二个lapply中,我明确地返回修改后的数据框。

答案 1 :(得分:4)

@joran的回答在很大程度上重叠了我的风格和“你可能想要以不同的方式做这件事”的消息。然而,本着“给人一条鱼,你喂他一天;给他一根尖锐的棍子,他可以戳自己的眼睛”的精神......

这是一个以你想要的方式做你想做的事情的功能:

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
}

以下是两个替代函数,它们小写列名并返回结果:

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

我在这里包含plyr::rename是为了完整性,尽管在这种情况下它实际上比它的价值更麻烦。

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)

答案 2 :(得分:1)

这不能直接回答你的问题,但它可以解决你想要解决的问题;你可以通过不同的名称合并data.frames,例如:

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)