5

R 2.15.0data.table 1.8.9

d = data.table(a = 1:5, value = 2:6, key = "a")

d[J(3), value]
#   a value
#   3     4

d[J(3)][, value]
#   4

我希望两者都能产生相同的输出(第二个),我相信他们应该

为了澄清这不是J语法问题,相同的期望适用于以下(与上述相同)表达式:

t = data.table(a = 3, key = "a")
d[t, value]
d[t][, value]

我希望以上两者都能返回完全相同的输出。

所以让我重新表述这个问题- 为什么(data.table设计成这样)列会自动打印出来d[t, value]

更新(基于下面的答案和评论):感谢@Arun 等人,我现在了解设计原因。上面打印密钥的原因是因为每次通过语法进行合并时都有一个隐藏存在,那就是密钥。以这种方式设计的原因似乎如下 - 由于必须在合并时执行操作,因此如果您要通过合并的键来执行此操作,不妨利用这一点而不是执行另一个操作。data.tableX[Y]bybyby

话虽如此,我相信这是一个语法设计缺陷。我阅读data.table语法的方式d[i, j, by = b]

take d,应用i操作(是子集或合并或诸如此类),然后执行j表达式“by” b

by-without-by 打破了这种阅读并介绍了一个必须特别考虑的案例(我是否合并iby只是合并的关键,等等)。我相信这应该是的工作-在合并的一个特定情况下data.table做出更快的值得称赞的努力,当等于键时,应该以另一种方式完成(例如,通过内部检查表达式是否实际上是合并的关键)。data.tablebyby

4

4 回答 4

11

编辑编号 Infinity: Faq 1.12准确回答了您的问题:( FAQ 1.13也有用/相关,此处未粘贴)。

1.12 X[Y]和merge(X,Y)有什么区别?
X[Y] 是一个连接,使用 Y(或 Y 的键,如果有的话)作为索引来查找 X 的行。Y[X] 是一个连接,使用 X(或 X 的键,如果有的话)作为索引来查找 Y 的行。merge(X,Y)1 同时做这两种方式。X[Y] 和 Y[X] 的行数通常不同;而 merge(X,Y) 和 merge(Y,X) 返回的行数是相同的。但是这忽略了要点。大多数任务都需要在连接或合并后对数据执行某些操作。为什么要合并所有数据列,然后只使用其中的一小部分?
您可能会建议merge(X[,ColsNeeded1],Y[,ColsNeeded2]),但这需要数据子集的副本,并且需要程序员确定需要哪些列。data.table 中的 X[Y,j] 为您一步完成所有这些. 当您编写时X[Y,sum(foo*bar)], data.table 会自动检查 j 表达式以查看它使用了哪些列。它只会对这些列进行子集化;其他的被忽略。仅为 j 使用的列创建内存,并且 Y 列在每个组的上下文中享受标准的 R 回收规则。假设 foo 在 X 中,而 bar 在 Y 中(以及 Y 中的 20 个其他列)。不是 X[Y,sum(foo*bar)] 比合并后跟一个子集更快地编程和运行吗?


旧答案对回答 OP 的问题没有任何帮助(来自 OP 的评论),保留在这里,因为我相信它确实如此)。

当您为jliked[, 4]d[, value]in提供值时data.table, thej被评估为expression。从 data.table FAQ 1.1 on access DT[, 5](第一个常见问题解答):

因为,默认情况下,与 data.frame 不同,第二个参数是在 DT 范围内计算的表达式。5 评估为 5。

因此,在您的情况下,首先要了解的是:

d[, value] # produces a "vector"
# [1] 2 3 4 5 6

当查询是基本索引时,这没有什么不同,例如:i

d[3, value] # produces a vector of length 1
# [1] 4

但是,当is 本身是 a时,情况就不同了。引言(第 6 页):idata.tabledata.table

d[J(3)] # is equivalent to d[data.table(a = 3)]

在这里,您正在执行join. 如果您只是这样做,d[J(3)]那么您将获得与该联接对应的所有列。如果你这样做,

d[J(3), value] # which is equivalent to d[J(3), list(value)]

既然你说这个答案对回答你的问题没有任何帮助,我会指出我相信你的“改写”问题的答案在于:--->那么你只会得到那个专栏,但既然你正在表演连接,键列也将被输出(因为它是基于键列的两个表之间的连接)。


编辑:在您的第二次编辑之后,如果您的问题是为什么会这样?,那么我会不情愿地(或者说是无知地)回答,Matthew Dowle 的设计是为了区分 data.tablejoin-based-subsetindex-based-subsetting 操作。

您的第二种语法相当于:

d[J(3)][, value] # is equivalent to:

dd <- d[J(3)]
dd[, value]

在哪里, in dd[, value]j被评估为一个表达式,因此你得到一个向量。


要回答您的第三个修改问题:第三次,这是因为它是基于键列的两个 data.tables 之间的 JOIN 。如果我加入两个data.tables,我期望一个data.table

data.table介绍开始,再次:

将 data.table 传递到 data.table 子集类似于基础 R 中的 A[B] 语法,其中 A 是矩阵,B 是 2 列矩阵。事实上,base R 中的 A[B] 语法启发了 data.table 包。

于 2013-04-18T21:53:41.670 回答
6

从 开始data.table 1.9.3,默认行为已更改,下面的示例产生相同的结果。要获得by-without-by结果,现在必须指定一个显式by=.EACHI

d = data.table(a = 1:5, value = 2:6, key = "a")

d[J(3), value]
#[1] 4

d[J(3), value, by = .EACHI]
#   a value
#1: 3     4

这是一个稍微复杂一点的例子,说明了区别:

d = data.table(a = 1:2, b = 1:6, key = 'a')
#   a b
#1: 1 1
#2: 1 3
#3: 1 5
#4: 2 2
#5: 2 4
#6: 2 6

# normal join
d[J(c(1,2)), sum(b)]
#[1] 21

# join with a by-without-by, or by-each-i
d[J(c(1,2)), sum(b), by = .EACHI]
#   a V1
#1: 1  9
#2: 2 12

# and a more complicated example:
d[J(c(1,2,1)), sum(b), by = .EACHI]
#   a V1
#1: 1  9
#2: 2 12
#3: 1  9
于 2014-03-14T15:10:00.700 回答
4

不是意外行为,而是记录在案的行为。Arun 在FAQ 中做了很好的解释和演示,其中清楚地记录了这一点。

有一个功能请求FR 1757建议drop在这种情况下使用参数

实施时,您想要的行为可能会被编码

d = data.table(a = 1:5, value = 2:6, key = "a")

d[J(3), value, drop = TRUE]
于 2013-04-19T00:04:46.913 回答
3

我同意阿伦的回答。这是另一种说法:在进行连接之后,您通常会将连接列用作参考或作为进一步转换的输入。所以你保留它,你可以选择用(更迂回的)双重[语法丢弃它。从设计的角度来看,经常保留相关信息,然后在需要时丢弃,比尽早丢弃并冒丢失难以重建的数据的风​​险更容易。

您希望保留连接列的另一个原因是您可以在执行连接的同时执行聚合操作(不带 by 的 by)。例如,通过包含 join 列,此处的结果更加清晰:

d <- data.table(a=rep.int(1:3,2),value=2:7,other=100:105,key="a")
d[J(1:3),mean(value)]
#   a  V1
#1: 1 3.5
#2: 2 4.5
#3: 3 5.5
于 2013-04-18T23:39:55.050 回答