data.table 何时保留列名?

8

一些 J 表达式会保留列名,而有些则不会:

library(data.table)
d = data.table(hello = 1)
d[, .(hello)]
#    hello
# 1:     1
d[, c(.(hello))]
#    V1
# 1:  1
d[, {.(hello)}]
#    hello
# 1:     1
d[, {1; .(hello)}]
#    V1
# 1:  1
d[, .(get("hello"))]
#    V1
# 1:  1
d[, mget("hello")]
#    hello
# 1:     1
d[, c(mget("hello"))]
# Error: value for ‘hello’ not found  # WTF?
d[, {1; mget("hello")}]
#    hello
# 1:     1

一般规则是什么?


1
我认为你的意思是“推断”而不是“保留”,答案总是在容易时,有时在困难时。 - eddi
这个 d[, c(mget("hello"))] 不起作用,但是这个 d[, list(mget("hello"))] 可以。 - Taher A. Ghaleb
1个回答

8

这其实并不是什么神秘的事情。首先请注意,在data.table中,.list的速记符号。有了这个想法,下面是正在发生的事情。

你的每一个表达式都会产生一个无名称的列表或向量,除了mget会生成一个有名称的列表。这就是为什么mget的示例具有命名结果的原因。在所有其他示例中,data.table只在非常简单的表达式中推断出名称,这些表达式等同于list(items)。还有一些更多的情况需要使用.SD才能获得名称,但通常来说——如果你没有命名它(如mget所做的那样)并且它比list(items)更复杂,那么不要期望名称推断。


那么问题似乎是什么data.frame的“非常简单的表达式,等同于list(items)”的想法。 显然,{.(hello)}是,而c(.(hello))不是。 我不知道规则是什么。 - Kodiologist
1
identical(c(list("hello")), list("hello"))TRUE,因此它们在语义上肯定是等价的。显然差异与语法有关。 - Kodiologist
1
你说得对,恰好在这个特定的输入上,函数c与身份相同。但一般情况下,这并不是正确的,你也不应该指望计算机具有如此高级别的表达式理解能力来弄清楚它。无论“这是目前的扣除清单”的答案是什么——都不能保证未来不会改变/扩展/缩小(这就是为什么我不介意查看代码为您编译它——它在那里供您查看)。唯一可预期的事情是 list(...)。对于其他所有内容,如果您想要确定性——请为其命名列。 - eddi
1
@Kodiologist 如果没有提供它们,data.table必须在评估之前推断名称,并且identical(quote(c(list("hello"))), quote(list("hello")))不是TRUE。经过初步查看源代码,我相信data.table实际上检查j表达式是否为list的调用。如果您将其包装在c中,则变成了对c的调用。 - Roland
4
看,identical(quote({list("hello")}), quote(list("hello")))FALSE,但{.(hello)}会推断出名称,而{{.(hello)}}则不会。也许将来会这样,也许不会。也许将来{.(hello)}也会停止推断,并严格限制为list.。我已经反复强调过无数次 - 我只看到在担心不确定性时这个问题很重要,但有解决方案。除此之外,我没有看到这个问题的价值。 - eddi
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接