12

我正在尝试重命名多个data.frames 的列。

举个例子,假设我有一个data.framesdfAdfB的列表dfC。我编写了一个函数changeNames来相应地设置名称,然后lapply按如下方式使用:

dfs <- list(dfA, dfB, dfC)
ChangeNames <- function(x) {
    names(x) <- c("A", "B", "C" )  
}
lapply(dfs, ChangeNames)

但是,这并没有按预期工作。似乎我没有将新名称分配给data.frame,而只是创建新名称。我在这里做错了什么?

先感谢您!

4

3 回答 3

15

这里有两件事:

  • 1)你应该从你的函数中返回你想要的值。否则,将返回最后一个值。在你的情况下,那是names(x). 因此,您应该添加作为最后一行,return(x)或者简单地添加x. 所以,你的函数看起来像:

    ChangeNames <- function(x) {
        names(x) <- c("A", "B", "C" )
        return(x)
    }
    
  • 2)lapply不会通过引用修改您的输入对象。它适用于副本。因此,您必须将结果分配回去。或者另一种选择是使用for-loops而不是lapply

    # option 1
    dfs <- lapply(dfs, ChangeNames)
    
    # option 2
    for (i in seq_along(dfs)) {
        names(dfs[[i]]) <- c("A", "B", "C")
    }
    

即使使用for-loop,您仍然会制作副本(因为names(.) <- .确实如此)。您可以使用tracemem.

df <- data.frame(x=1:5, y=6:10, z=11:15)
tracemem(df)
# [1] "<0x7f98ec24a480>"
names(df) <- c("A", "B", "C")
tracemem(df)
# [1] "<0x7f98e7f9e318>"

如果要通过引用进行修改,可以使用data.table包的setnames功能:

df <- data.frame(x=1:5, y=6:10, z=11:15)
require(data.table)
tracemem(df)
# [1] "<0x7f98ec76d7b0>"
setnames(df, c("A", "B", "C"))
tracemem(df)
# [1] "<0x7f98ec76d7b0>"

您会看到df映射到的内存位置没有改变。名称已通过引用进行了修改。

于 2013-08-22T09:23:15.687 回答
12

如果数据框不在列表中,而只是在全局环境中,则可以使用字符串名称向量来引用它们。

dfs <- c("dfA", "dfB", "dfC")

for(df in dfs) {
  df.tmp <- get(df)
  names(df.tmp) <- c("A", "B", "C" ) 
  assign(df, df.tmp)
}

编辑

为了简化上面的代码,您可以使用

for(df in dfs)
  assign(df, setNames(get(df),  c("A", "B", "C")))

或使用data.table不需要重新分配的。

for(df in c("dfA", "dfB"))
  data.table::setnames(get(df),  c("G", "H"))
于 2015-05-13T03:14:37.077 回答
-1

我遇到了导入公共数据集的问题,并且必须重命名每个数据帧并重命名每个数据帧中的每一列以修剪空格、小写字母并用句点替换内部空格。

结合上述方法得到了我:

for (eachdf in dfs)
  df.tmp <- get(eachdf) 
    for (eachcol in 1:length(df.tmp))
      colnames(df.tmp)[eachcol] <-
      str_trim(str_to_lower(str_replace_all(colnames(df.tmp)[eachcol], " ", ".")))
      }
  assign(eachdf, df.tmp) 
}
于 2016-03-23T00:26:58.710 回答