我创建了小数据表DT=data.table(a=1:2,a=1:2)
如果我使用名称(DT)<;-c(“b”、“b”)
我得到一个警告
“名称”中的
。表`(`*tmp*`,值=c(“b”,“b”):
名称(x)<-值语法复制整个表。这是由于<;-在R本身。请更改为setnames(x、旧、新),它不会复制并且速度更快。请参阅帮助(“设置名称”)。如果现在不方便更改,您可以安全地忽略此警告。设置选项(warn=2)会将此警告变为错误,因此您可以使用traceback()查找并更改您的姓名<;-电话。
但如果我使用setnames(DT,names(DT),c(“b”,“b”)
,那么我会得到错误
集合名中的错误(DT,名称(DT),c(“b”,“b”):
“旧”中存在一些重复项:a
如果相同的示例使用data.frame而不是DT=data.frame(a=1:2,a=1:2)
并使用names(DT)<;-c(“b”,“b”)
,那么我不会得到任何错误
不要提供old
和new
这样就不会有问题。但是,这不是问题所在。在base::data.frame
中,不能有同名列,因此
#您实际得到的。。。
DT=数据帧(a=1:2,a=1:2);名称(DT)
#[1] a“a.1”
但是在data.table
中,似乎可以有同名的列
DT=data.table(a=1:2,a=1:2);名称(DT)
[1] “a”“a”
但是setnames
抛出了一个错误,我猜这是因为它不知道a
在调用a
两列时所指的是哪一列。将data.frame
路由到data.table
时不会出错,因为您没有重复的列名
首先,我要说的是,不要使用相同名称的列,如果您计划以编程方式使用data.table
(但是正如@MatthewDowle在评论中指出的那样,这是一种设计选择,让用户在data.table
中拥有最大自由度),这是一件非常糟糕的事情
如果需要这样做,则只使用给定的old
参数使用setnames
,当未给定new
时,该参数实际上将被视为new
名称。如果传入old
名称和一个新名称向量,则会找到旧名称并将其更改为相应的新名称(因此,old
和new
必须在setnames
与3个参数一起使用时具有相同的长度)。setnames
将通过以下方式捕捉任何歧义:
如果(有(重复的(旧的)))
停止(“某些重复项存在于'old':”,粘贴(old[duplicated(old)],
折叠“”,“”)
如果(有(重复的(名称(x)))
stop(“'old'是字符,但有重复的列名:”,
粘贴(名称(x)[重复(名称(x))],折叠=“,”)
当只提供old
时,setnames
将使用将
,因此从头到尾old
中的名称重新分配到DT
的列中。Call(Csetcharvec,names(x),seq_-along(names(x)),old)
DT=data.table(a=1:2,a=1:2)
集合名(DT,c(“b”,“b”))
DT
#b b
#1: 1 1
#2: 2 2
根据要求从Matthew处添加。在?setnames
中有一些背景:
一般来说,使用列号不是很好的编程实践
这就是为什么setkey和setkeyv只接受列
名称,以及为什么建议使用setnames()中的old作为名称
使用列号,那么bug(可能是无声的)就更容易蔓延
如果在代码中的其他地方进行了更改,则会随着时间的推移将其添加到代码中
您的代码;例如,如果您在几个月内添加、删除或重新排序列
此时,按列编号设置的setkey将引用不同的列,
可能在没有警告的情况下返回不正确的结果。(类似的
SQL中存在这样一个概念,“select*from…”被认为是不好的
需要健壮、可维护的系统时的编程风格。)如果
您确实希望使用列编号,这是可能的,但是有意的
稍微难一点;例如,setkeyv(DT,colnames(DT)[1:2])
[截至2017年7月,上述注释不再出现在?setnames
中,但在常见问题解答的顶部附近讨论了该问题,vignette('datatable-FAQ')
]
因此,setnames
的思想是通过名称很容易地更改一个列名
设置名称(DT,“旧名称”、“新名称”)
如果“oldname”
不是一个列名,或者对您的意图有任何歧义(无论是现在的数据中,还是在您的同事更改了源数据库或其他上游代码或将自己的数据传递给您的模块后的几个月内)然后,data.table
将为您捕获它。在base中,这实际上很难像setnames
那样轻松完成(包括安全检查)