开始使用 data.table
包(作者/维护者:Matt Dowle) . 很棒的套餐 . 我喜欢我可以写 dt[, x1]
而不是 dt[, dt$x1]
或 df["x1"]
,对于data.table dt
,列名 x1
,data.frame df
. 能够直接传递列名是data.table的一个有吸引力的特性 . 但是在列名称周围省略引号(写 x1
而不是 "x1"
)并不总是可行的 . 为什么?
编程问题:是否有任何理由不能始终将列名向量直接传递给data.table或包提供的辅助函数?例如,已经为data.table包重写了 subset
, merge
和 melt
函数,但是 subset
可以直接处理列名, merge
和 melt
不能(见下文) .
澄清一下,我的问题不是何时或如何,而是为什么 . 有很好的相关讨论,非常有用的提示,例如Select / assign to data.table variables which names are stored in a character vector和r - passing variables as data.table column names . 有了这些答案和一些试验和错误,我能够找到报价/不引用区别的方法 . 我的问题是为什么目前不能总是在列名称周围省略引号:它有设计吗?这是一个过渡性的情况吗?有编程困难吗?
下面,为了清楚起见,我举一些例子并对这些例子进行编号
# load the package
library("data.table") # because I cannot do install.packages(data.table)!!
(i)
# 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")
我可以用 id = 1:10
或 "id" = 1:10
定义data.table,但我必须用 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
如果要在列名中查找密钥,那么'd think finding ' id'对于密钥来说应该相当容易吗?以编程方式声音是否允许删除 key
的RHS上的引号?
(ii)
我可以 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
不错,灵活 .
(iii)
我可以 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
的方式接受列向量?
(iv)
同样, melt
必须使用带引号的列名(或对应于列号的整数) .
帮助描述是特定的 melt
接受"character vectors",而 merge
的帮助只是"vectors of column names,",但显然 merge
与 melt
字符向量一样 .
(v)
在 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)]
不太可能是这里所需的命令 - dt[i, j]
的 j
参数非常需要列表 .
(vi)
但是,在 dt[i, j]
的 j
参数内,"assignment by reference"运算符 :=
的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
错误消息不是特别有启发性 . 但现在我记得常见问题解答的建议,"If 2 or more columns are required, use list() or .() instead."傻我, 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).
(vii)
dt[i]
的 i
参数也用于接受未加引号的列,即"expression of column names"
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"
传递,并且两种情况都可以完成 . 这些差异可能会给像我这样的新用户造成混淆 . 我怀疑这两种方法共存的原因不止一个 . 如果有人可以澄清这个问题我会很感激,对于我的一些例子,如果不是所有的话 .
1 回答
(i),(iii)和(iv)听起来像功能请求(FR);见here(所以,是的,这部分是由于
data.table
尚未达到完全成熟) .至于(v)你说“
dt[, c(x1, x2)]
不太可能是这里所需的命令”,但实际上我已经看到了c
中c
的使用情况就是我所追求的 . 像(v)这样的情况就是这样[.data.table
的with
参数适用于 .在(vi)和其他地方,你建议"The manual only says 'a vector of column names', but experimentation suggests they must be quoted";但我认为这是毫不含糊的 . 列名称向量表示
character
向量,c(x1,x2)
不是,除非x1
和x2
某处定义为character
向量本身 . 您还可以在GitHub上添加FR文档 .在_(vii)之后我是'm not sure what you',但在
i
中,名称向量用于连接或键控子集(也是连接形式);见vignette on fast subsetting .