data.table join和j-expression意外行为

edd*_*ddi 5 r data.table

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
Run Code Online (Sandbox Code Playgroud)

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

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

t = data.table(a = 3, key = "a")
d[t, value]
d[t][, value]
Run Code Online (Sandbox Code Playgroud)

我希望以上两个都返回完全相同的输出.

那么让我重新解释一下这个问题 - 为什么(data.table这样设计)关键列会自动打印出来d[t, value]

更新(根据下面的答案和评论):感谢@Arun等人,我理解设计 - 为什么现在.究其原因,上面打印的关键是因为有一个隐藏当前每次你做一个时间data.table通过合并X[Y]语法,这by是关键.它以这种方式设计的原因似乎如下 - 因为by必须在合并时执行操作,人们可以利用它而不是另外做另一个,by如果你要通过合并的键来做到这一点.

现在说,我认为这是一个语法设计缺陷.我阅读data.table语法的方式d[i, j, by = b]

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

逐个打破这个阅读并介绍一个人必须具体思考的案例(我合并i,by只是合并的关键等).我认为这应该是data.table- 在data.table合并的一个特定情况下,当by等于键时,应该以另一种方式完成(例如通过内部检查by表达式是否实际上是合并的关键).

Aru*_*run 11

编辑号码无限:常见问题1.12 正好回答了你的问题:(也很有用/相关的是FAQ 1.13,这里没有粘贴).

1.12 X [Y]和合并(X,Y)有什么区别?
X [Y]是一个连接,使用Y(或Y的密钥,如果有的话)作为索引查找X的行.Y [X]是一个连接,使用X(或X的键,如果有的话)作为索引查找Y的行.merge(X,Y)1同时执行两种方式.X [Y]和Y [X]的行数通常为dier; 而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的评论),保留在这里,因为我相信它确实如此).

当您为jlike d[, 4]d[, value]in 赋值时data.table,将j其评估为expression.从data.table FAQ 1.1访问DT[, 5](第一个常见问题解答):

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

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

d[, value] # produces a "vector"
# [1] 2 3 4 5 6
Run Code Online (Sandbox Code Playgroud)

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

d[3, value] # produces a vector of length 1
# [1] 4
Run Code Online (Sandbox Code Playgroud)

然而,当它本身是a 时,这是不同idata.table.从data.table介绍(第6页):

d[J(3)] # is equivalent to d[data.table(a = 3)]
Run Code Online (Sandbox Code Playgroud)

在这里,你正在表演join.如果您这样做,d[J(3)]那么您将获得与该连接相对应的所有列.如果你这样做,

d[J(3), value] # which is equivalent to d[J(3), list(value)]
Run Code Online (Sandbox Code Playgroud)

既然你说这个答案没有回答你的问题,我会指出你的"改写"问题的答案在哪里,我相信:---> 然后你就会得到那个专栏,但是因为你在表演一个连接,键列也将被输出(因为它是基于键列的两个表之间的连接).


编辑:在你的第二次编辑之后,如果你的问题是为什么呢?那么我不情愿(或者说是无知)回答,马修道尔设计的是为了区分data.table join-based-subsetindex-based-subsetting操作.

您的第二种语法相当于:

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

dd <- d[J(3)]
dd[, value]
Run Code Online (Sandbox Code Playgroud)

其中,再次,在dd[, value],j被评估为的表达式,因此,你得到的载体.


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

data.table介绍,再次:

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

  • @Arun +100为此!:-) (6认同)

edd*_*ddi 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
Run Code Online (Sandbox Code Playgroud)

这是一个稍微复杂的例子,说明了不同之处:

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
Run Code Online (Sandbox Code Playgroud)