当前位置:  开发笔记 > 编程语言 > 正文

data.table:为什么不能总是直接传递列名?

如何解决《data.table:为什么不能总是直接传递列名?》经验,为你挑选了1个好方法。

开始使用该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可以直接处理的列名,mergemelt不能(见下文).

澄清一下,我的问题不是何时如何,而是为什么.有非常有用的提示有很好的相关讨论,例如,选择/分配给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简单地说明"列名称的向量",但显然mergemelt字符向量一样.

(五)

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

请注意,如果想法是子集两列x1x2,即应当里面做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> MichaelChiri..:

(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,名称的向量用于连接或键控子集(也是一种连接形式); 看快速子集的小插图.


更重要的是,`c(x1,x2)`**c**包含对象`x1`和`x2`(所以它只是另一种类型为'x1`和`x2的最通用类型的向量` - eg,如果`x1`是`numeric`和`x2``integer`,`c(x1,x2)`是`numeric`); 如果在另一个对象(`list`,`data.frame`,`data.table`等)的范围内进行评估,则这些对象是列名或元素名; 否则(简化一点),R使用在全球环境中发现的东西.字符(即非字母数字)被_always_解释为R的变量名.
推荐阅读
我我檬檬我我186
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有