不提供old
,new
你就不会有问题。然而,这不是问题。在base::data.frame
你不能有同名的列,所以......
# What you actually get...
DT = data.frame(a=1:2, a=1:2); names(DT)
#[1] "a" "a.1"
但似乎data.table
你可以有同名的列......
DT = data.table(a=1:2, a=1:2); names(DT)
[1] "a" "a"
但是setnames
会抛出一个错误,我猜是因为它不知道a
在调用两列时它指的是哪一列a
。data.frame
转到路由时不会出错,data.table
因为您没有重复的列名。
首先,我会说不要创建具有相同名称的列,如果您打算以编程方式使用您的列,这是一件非常糟糕的事情data.table
(但正如@MatthewDowle 在评论中指出的那样,这是为用户提供最大自由的设计选择中data.table
)。
如果你需要这样做,那么setnames
只使用给定的参数,当没有给出时old
,它实际上将被视为new
名称。new
如果您传入old
名称和新名称的向量,则会找到旧名称并将其更改为相应的新名称(因此old
,当与 3 个参数一起使用new
时,长度必须相同)。将通过以下方式捕捉任何歧义:setnames
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 = ","))
当just old
提供setnames
时,将重新分配名称 fromold
到DT
column-wise using的列.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
应要求从 Matthew 添加。里面有?setnames
一些背景:
一般来说,使用列号而不是名称不是好的编程习惯。这就是为什么 setkey 和 setkeyv 只接受列名,以及为什么建议 setnames() 中的 old 为名称。如果您使用列号,那么如果在代码的其他地方进行了更改,那么随着时间的推移,错误(可能是无声的)会更容易地潜入您的代码;例如,如果您在几个月内添加、删除或重新排序列,则按列号设置的键将引用不同的列,可能会返回不正确的结果而没有警告。(类似的概念存在于 SQL 中,当需要一个健壮、可维护的系统时,“select * from ...”被认为是糟糕的编程风格。)如果您真的希望使用列号,这是可能的,但故意稍微难一点;例如,setkeyv(DT,colnames(DT)[1:2])。
[截至 2017 年 7 月,上述注释不再出现在 中?setnames
,但该问题在常见问题解答顶部附近讨论,vignette('datatable-faq')
.]
所以想法setnames
是很容易地按名称更改一列名称。
setnames(DT, "oldname", "newname")
如果"oldname"
不是列名,或者您的意图有任何歧义(在现在的数据中,或者在您的同事更改源数据库或上游其他代码或将他们自己的数据传递给您的模块后的几个月后),那么data.table
将为你抓住它。这实际上很难在基地中轻松setnames
完成(包括安全检查)。