开始使用该data.table
包(作者/维护者:Matt Dowle).很棒的套餐.我喜欢我可以写,dt[, x1]
而不是说,dt[, dt$x1]
或者df["x1"]
,对于data.table dt
,列名x1
,data.frame df
.能够直接传递列名是data.table的一个有吸引力的特性.但是在列名称周围省略引号(写x1
而不是"x1"
)并不总是可行的.为什么?
编程问题:是否有任何理由不能始终将列名向量直接传递给data.table或包提供的辅助函数?例如,subset
,merge
,和melt
功能已被改写为data.table包,但同时subset
可以直接处理的列名,merge
而melt
不能(见下文).
澄清一下,我的问题不是何时或如何,而是为什么.有非常有用的提示有很好的相关讨论,例如,选择/分配给data.table变量,这些变量名称存储在字符向量中,r - 将变量作为data.table列名称传递.有了这些答案和一些试验和错误,我就能找到报价/不引用区别的方法.我的问题是为什么目前不可能总是省去列名称的引号:它有设计吗?这是一个过渡性的情况吗?有编程困难吗?
下面,为了清楚起见,我举一些例子并对这些例子进行编号
# load the package library("data.table") # because I cannot do install.packages(data.table)!!(一世)
# make a data.table set.seed(1) dt <- data.table(id = 1:5, x1 = 1:5, x2 = 5:1, x3 = round(runif(5, 1, 5), 0), key = "id")
我可与定义data.table id = 1:10
或"id" = 1:10
,但我必须定义与键key = "id"
为key = id
不能正常工作:
dt <- data.table(id = 1:5, x1 = 1:5, x2 = 5:1, x3 = round(runif(5, 1, 5), 0), key = id) ##Error in data.table(id = 1:5, x1 = 1:5, x2 = 5:1, x3 = round(runif(5, : ## object 'id' not found
你认为如果在列名中寻找密钥,找到'id'对于密钥应该相当容易吗?以编程方式声音是否允许删除RHS上的引号key
?
我可以subset
使用列向量或列名向量:
subset(dt, select = c(x1, x3)) ## x1 x3 ##1: 1 2 ##2: 2 2 ##3: 3 3 ##4: 4 5 ##5: 5 2 subset(dt, select = c("x1", "x3")) ## x1 x3 ##1: 1 2 ##2: 2 2 ##3: 3 3 ##4: 4 5 ##5: 5 2
不错,灵活.
(ⅲ)我可以merge
使用列名向量:
merge(dt, dt, by = c("x1", "x2")) ## id x1 x2 x3 ##1: 1 1 5 2 ##2: 2 2 4 2 ##3: 3 3 3 3 ##4: 4 4 2 5 ##5: 5 5 1 2
(愚蠢的例子是!)但不是列的向量:
merge(dt, dt, by = c(x1, x2)) ##Error in merge.data.table(dt, dt, by = c(x1, x2)) : object 'x1' not found
是否存在一些merge
阻止它接受列向量的方法subset
呢?
同样,melt
必须使用带引号的列名(或对应于列号的整数).
帮助描述是特定的,melt
接受"字符向量",而帮助merge
简单地说明"列名称的向量",但显然merge
与melt
字符向量一样.
在j
参数的情况下,引用变量名称通常不是正确的方法:
# Good: dt[, .(x1, x2)] ## x1 x2 ##1: 1 5 ##2: 2 4 ##3: 3 3 ##4: 4 2 ##5: 5 1 # Bad dt[, .("x1", "x2")] ## V1 V2 ##1: x1 x2 # This feature is well documented in the FAQs # FAQ 2.3: "I'm using c() in the j and getting strange results."
不完全熟悉的读者注意data.tables
这.()
是一个简写list()
,这dt[, c(x1, x2)]
不太可能是这里所需的命令 - 非常需要一个列表的j
参数dt[i, j]
.
但是,在j
参数范围内dt[i, j]
,"按参考分配"运算符的LHS :=
有一个令人困惑的约定.
如果LHS是单列,则可以不带引号传递.但是如果它有多个列,则它们必须作为引用列名的向量传递.该手册仅说"列名称的向量",但实验表明它们必须引用:
# Good: dt[, c("x1", "x2") := NULL][] ## id x3 ##1: 1 2 ##2: 2 2 ##3: 3 3 ##4: 4 5 ##5: 5 2 # Bad: dt[, c(x1, x2) := NULL] ##Error in eval(expr, envir, enclos) : object 'x1' not found
错误消息不是特别有启发性.但现在我记得FAQ的建议,"如果需要2个或更多列,请使用list()或.()代替." 愚蠢的我,c(x1, x2)
无法工作,因为没有办法分辨到哪里x1
结束和x2
开始.但是,.(x1, x2)
可以工作,不是吗?
# Bad: dt[, .(x1, x2) := NULL] ##Error in eval(expr, envir, enclos) : object 'x1' not found
不,考虑到所有事情,LHS :=
期望引用列名称的向量.手册应该更新,或者,如果可行的话,应data.table
扩展到接受LHS上未加引号的列的列表.
等一下.要删除多个列名,我可以将引用名称列表传递给LHS吗?不是.列表通常是可取的,但不是LHS的:=
.错误消息很明确:
# Bad: dt[, .("x1", "x2") := NULL][] ##Error in `[.data.table`(dt, , `:=`(.("x1", "x2"), NULL)) : ## LHS of := must be a symbol, or an atomic vector (column names or positions).(ⅶ)
该i
的参数dt[i]
设计也接受不带引号的列,即一个"列名的表达"
dt[.(x1, x2)] ## id x1 x2 x3 V2 ##1: 1 1 5 2 5 ##2: 2 2 4 2 4 ##3: 3 3 3 3 3 ##4: 4 4 2 5 2 ##5: 5 5 1 2 1
请注意,如果想法是子集两列x1
和x2
,即应当里面做j
的说法,即dt[,.(x1, x2)]
dt[.("x1", "x2")] ##Error in bmerge(i, x, leftcols, rightcols, io, xo, roll, rollends, nomatch, : ## typeof x.id (integer) != typeof i.V1 (character) dt[c(x1, x2)] ##id x1 x2 x3 ## 1: 1 1 5 2 ## 2: 2 2 4 2 ## 3: 3 3 3 3 ## 4: 4 4 2 5 ## 5: 5 5 1 2 ## 6: 5 5 1 2 ## 7: 4 4 2 5 ## 8: 3 3 3 3 ## 9: 2 2 4 2 ##10: 1 1 5 2 dt[c("x1", "x2")] ##Error in bmerge(i, x, leftcols, rightcols, io, xo, roll, rollends, nomatch, : ## typeof x.id (integer) != typeof i.V1 (character)
我在这里展示了几种情况,其中列必须作为x1
或"x1"
两者都可以传递的情况.这些差异可能会给像我这样的新用户造成混淆.我怀疑这两种方法共存的原因不止一个.如果有人能澄清这个问题,我会很感激,对于我的一些例子,如果不是所有的话.
(i),(iii)和(iv)听起来像功能请求(FR); 看到这里(所以,是的,这部分是由于data.table
没有达到完全成熟).
至于(v)你说" dt[, c(x1, x2)]
在这里不太可能成为理想的命令",但实际上我已经看到了c
内部使用内部的j
情况就是我所追求的.像(v)这样的情况就是with
争论的内容[.data.table
.
在(vi)和其他地方,你建议"手册只说'一个列名矢量',但实验表明它们必须引用"; 但我认为这是毫不含糊的.列名称的character
向量表示向量c(x1,x2)
,除非x1
并且x2
某处定义为character
向量本身.您还可以在GitHub上添加FR文档.
我不确定你在(vii)中所追求的是什么,但是i
,名称的向量用于连接或键控子集(也是一种连接形式); 看快速子集的小插图.