R data.table更改R名称

use*_*940 25 r data.table

我创建了小数据表DT = data.table(a=1:2, a=1:2).

如果我使用 names(DT) <- c("b","b")

我收到警告

In `names<-.data.table`(`*tmp*`, value = c("b", "b")) :
  The names(x)<-value syntax copies the whole table. This is due to <- in R itself. Please change to setnames(x,old,new) which does not copy and is faster. See help('setnames'). You can safely ignore this warning if it is inconvenient to change right now. Setting options(warn=2) turns this warning into an error, so you can then use traceback() to find and change your names<- calls.
Run Code Online (Sandbox Code Playgroud)

但如果我使用setnames(DT, names(DT), c("b","b"),那么我会收到错误

Error in setnames(DT, names(DT), c("b", "b")) : 
  Some duplicates exist in 'old': a
Run Code Online (Sandbox Code Playgroud)

如果相同的例子使用data.frame而不是DT = data.frame(a=1:2, a=1:2)使用, names(DT) <- c("b","b")那么我没有得到任何错误.

Sim*_*lon 32

不提供old,new你不会有问题.但是,这不是问题.在base::data.frame你不能有相同名称的列所以...

#  What you actually get...
DT = data.frame(a=1:2, a=1:2); names(DT)
#[1] "a"   "a.1"
Run Code Online (Sandbox Code Playgroud)

但似乎data.table你可以拥有相同名称的列......

DT = data.table(a=1:2, a=1:2); names(DT)
[1] "a" "a"
Run Code Online (Sandbox Code Playgroud)

但是setnames抛出一个错误,我猜是因为它不知道哪个a列在调用两列时都引用了a.在data.frame前往data.table路由时没有错误,因为您没有重复的列名.

首先我要说的是不要创建具有相同名称的列,如果您计划以编程方式使用,这是一件非常糟糕的事情data.table(但正如@MatthewDowle在评论中指出的那样,这是为用户提供最大自由度的设计选择in data.table).

如果你需要这样做,那么只使用给定setnamesold参数,实际上将被视为未给出的new名称new.如果传入old名称新名称的向量,则会找到旧名称,并将其更改为相应的新名称(因此old,newsetnames与3个参数一起使用时,必须具有相同的长度).setnames将通过以下方式捕捉任何含糊之处:

if (any(duplicated(old))) 
           stop("Some duplicates exist in 'old': ", paste(old[duplicated(old)],
                collapse = ","))
if (any(duplicated(names(x)))) 
           stop("'old' is character but there are duplicate column names: ", 
                paste(names(x)[duplicated(names(x))], collapse = ",")) 
Run Code Online (Sandbox Code Playgroud)

如果只是 old提供setnames将重新分配名字old到的列DT逐列使用.Call(Csetcharvec, names(x), seq_along(names(x)), old),所以从第一个到最后......

DT = data.table(a=1:2, a=1:2)
setnames(DT, c("b","b") )
DT
#   b b
#1: 1 1
#2: 2 2
Run Code Online (Sandbox Code Playgroud)

根据要求增加马修.在?setnames那里有一些背景:

一般来说,使用列号而不是名称是不好的编程习惯.这就是为什么setkey和setkeyv只接受列名,以及为什么建议将setnames()中的旧名称作为名称.如果您使用列号,那么如果代码中的其他地方发生了更改,那么随着时间的推移,错误(可能是静默的)可能会更容易蔓延到您的代码中; 例如,如果您在几个月内添加,删除或重新排序列,则按列号的setkey将引用不同的列,可能返回不正确的结果且没有警告.(在SQL中存在类似的概念,当需要健壮,可维护的系统时,"select*from ..."被认为是糟糕的编程风格.)如果你真的希望使用列号,那么它可能会有意但有点困难; 例如,setkeyv(DT,colnames(DT)[1:2]).

[截至2017年7月,上述说明不再出现?setnames,但问题在FAQ的顶部附近讨论,vignette('datatable-faq').]

因此,我们的想法setnames是通过名称轻松更改一个列名.

setnames(DT, "oldname", "newname")
Run Code Online (Sandbox Code Playgroud)

如果"oldname"不是列名称或有任何含糊不清了,你打算什么(无论是在数据现在还是在几个月的时间后,你的同事已经改变了源数据库或其他代码上游或已通过自己的数据到你的模块),然后data.table将抓住它.这实际上很难在基地进行,也很容易setnames做到(包括安全检查).

  • @MatthewDowle随时可以编辑以使其清楚*为什么*`data.table`为您提供这种能力以及为什么它比`base`更方便.我认为这是一个非常有用的功能. (2认同)

Ste*_*hen 5

setnames 可用于一次更改多个列名称:

setnames(DT, old = c("oldname1", "oldname2", "oldname3"), new = c("newname1", "newname2", "newname3"))
Run Code Online (Sandbox Code Playgroud)