knitr 被 data.table ':=' 赋值欺骗

knitr gets tricked by data.table `:=` assignment

提问人:Corvus 提问时间:3/7/2013 最后编辑:CommunityCorvus 更新时间:4/5/2017 访问量:5491

问:

似乎不明白这不应该导致文档的输出。有没有办法阻止这种行为?knitrDT[, a:=1]DT

示例文档:knitr

Data.Table Markdown
========================================================
Suppose we make a `data.table` in **R Markdown**
```{r}
DT = data.table(a = rnorm(10))
```
Notice that it doesn't display the contents until we do a
```{r}
DT
```
style command.  However, if we want to use `:=` to create another column
```{r}
DT[, c:=5]
```
It would appear that the absence of a equals sign tricks `knitr` into thinking this 
is to be printed.

针织产量:

enter image description here

这是一个错误还是一个错误?knitrdata.table

编辑

我刚刚注意到,当它使用代码时,这很奇怪。看看上面的输出。在我的源代码中,我有,但呈现的是knitrechoDT[, c:=5]knitr

DT[, `:=`(c, 5)]

奇怪。。。

编辑2:缓存

缓存似乎也有问题,但这一定是不同的原因,所以这里有一个单独的问题:为什么 data.table ':=' 的 knitr 缓存失败?:=

r data.table knitr

评论

1赞 Arun 3/7/2013
我发现很难理解这是一个错误。如果将其分配回 DT 会发生什么?(虽然我不确定 MatthewDowle 是否喜欢它)。data.table
1赞 Corvus 3/7/2013
好主意! 是一种可行的解决方法。我怀疑它一定是,但我不知道如何决定它是否应该输出 - 这纯粹是赋值的存在吗? 显然已经做了一些事情来停止控制台中的输出 - 也许这还不够全面?DT=DT[, :=]knitrknitrdata.table
1赞 Spacedman 3/7/2013
如果你将表达式包装在 invisible() 中,那么 knitr 不会打印它,这让我认为 knitr 比在有作业时不打印更聪明。但是我认为在这种情况下,也许data.table应该返回一个不可见的对象,因此data.table中可能存在错误。为什么它无论如何都不会被打印出来?那一定是data.table的业务......
0赞 Arun 3/7/2013
@Spacedman,对于(通过引用分配),是的,它没有。您必须使用 或 .:=print(DT[, LHS := RHS])DT[, LHS := RHS][]
2赞 Spacedman 3/7/2013
如果我从 R-forge 获取最新的 data.table 并使用 devtools 加载它,我确实会看到带有 .但只有在加载了 devtools 时。这个包裹确实有一些看起来很粗糙的污垢,到处都是和一个物体。嗯。DT[,c:=1]invisible().global

答:

20赞 Matt Dowle 3/7/2013 #1

2014 年 10 月更新。现在在 data.table v1.9.5 中:

:=不再打印以与提示符 #505 下的行为保持一致。测试的输出现在位于 data.table 的单元测试中。knitrknit("knitr.Rmd")

及相关:

if (TRUE) DT[,LHS:=RHS]现在不打印(感谢 Jureiss,#869)。添加了测试。为了让它工作,我们不得不忍受一个缺点:如果在函数末尾之前没有使用a,那么下次在提示符下键入时,不会打印任何内容。重复打印。为避免这种情况:在函数的最后一个之后包含一个。如果这是不可能的(例如,它不是您可以更改的功能),则保证在提示符下打印。和以前一样,在查询末尾添加额外的内容是建议更新然后打印的习惯用语;例如:=DT[]DTDTDT[]:=print(DT)DT[][]:=> DT[,foo:=3L][]



以前的答案留给后代(从 data.table v1.9.5 开始,业务不再完成,所以这不再是真的)......global$depthtrigger

为了清楚起见,我当时明白:在你不想要的时候打印。knitr

尝试在脚本开头增加一点。data.table:::.global$depthtrigger

目前,这将是 3 个:

data.table:::.global$depthtrigger
[1] 3

我不知道评估深度为堆栈增加了多少。但请先尝试将触发器更改为 4;即knitr

assign("depthtrigger", 4, data.table:::.global)

在脚本的末尾,确保将其设置回 3。如果 4 不起作用,请尝试 5,然后尝试 6。如果你到了 10 岁,就放弃,我会再想一想。8-3knitr

为什么会这样?

查看 v1.8.4 的新闻:

DT[,LHS:=RHS,...]不再打印 .这实现了 #2128 “尝试 再次无形地返回”。感谢这里的讨论:
v1.8.3 之前,在 R {data.table} 中使用“:=”时如何抑制输出?
http://r.789695.n4.nabble.com/Avoiding-print-when-using-tp4643076.html
常见问题 2.21 和 2.22 已更新。
DTDT[i,j:=value]

FAQ 2.21 为什么 DT[i,col:=value] 返回整个 DT?我期望没有可见值(与<-一致),或者消息或返回 包含已更新行数的值。并不明显的是 数据确实已通过参考进行更新。
这在 v1.8.3 中发生了变化 以满足您的期望。请升级。返回整个 DT (现在是看不见的)以便复合语法可以工作;例如, DT[i,done:=TRUE][,sum(done)]。返回更新的行数 当详细程度处于打开状态时,可以基于每个查询,也可以全局使用 选项(datatable.verbose=TRUE)。

FAQ 2.22 好的,谢谢。DT[i,col:=value] 的结果被无形地返回有什么困难?
R 内力 可见性 [.FunTab 的 eval 列的值(请参阅 src/main/names.c) for [ is 0 表示强制R_Visible开启(参见 R-Internals 第 1.6 节)。因此,当我们尝试 invisible() 或 直接将 R_Visible 设置为 0,在 src/main/eval.c 中评估 会再次强制它。要解决这个问题,关键是停止 尝试停止在 := 之后运行的 print 方法。相反,在里面:= 我们现在(从 v1.8.3 开始)设置了一个全局标志,print 方法用于 知道是否实际打印。

该全球标志是 .在顶部,你会看到它看着它。这是因为没有已知的方法可以禁止打印(如FAQ 2.22所解释的那样)。data.table:::.global$printdata.table:::print.data.table[

因此,在内部,它看起来可以看到这个调用有多“深”::=[.data.table

if (Cstack_info()[["eval_depth"]] <= .global$depthtrigger) {
    suppPrint = function(x) { .global$print=FALSE; x }
    # Suppress print when returns ok not on error, bug #2376.
    # Thanks to: https://stackoverflow.com/a/13606880/403310
    # All appropriate returns following this point are
    # wrapped i.e. return(suppPrint(x)).
}

本质上只是说:如果在提示符下运行,那么我知道 REPL 将对我的结果调用该方法,这超出了我的控制范围。好的,所以给定方法将要运行,我将通过设置一个标志在该方法中抑制它(因为运行的方法(即)是我可以控制的)。DT[,x:=y]printprintprintprintprint.data.table

在这种情况下,它以一种巧妙的方式模拟了 REPL。它不是真正的脚本,iiuc,否则无论如何都不会打印。但是,由于它是通过 模拟 REPL 的,因此从 运行的代码具有额外的深度。或类似的东西(我不知道).knitrDT[,x:=y]evalevalknitrknitr

这就是为什么我认为增加力量可以解决问题。depthtrigger

骇人听闻/粗鲁,我同意。但是,如果它有效,并且您让我知道哪个值有效,我可以更改为意识到并自动更改。或者任何更好的解决方案都是最受欢迎的。data.tableknitrdepthtrigger

评论

0赞 Spacedman 3/7/2013
啊!我只是花了半个小时从源代码中挖掘出来!为什么针对 C 堆栈深度进行测试是测试是否使结果不可见的良好测试?
0赞 Matt Dowle 3/7/2013
@Spacedman 这本身可能并不。但到目前为止,我发现唯一可以知道此调用返回的结果是否即将由 REPL 打印的方法。顺便说一句,内部还设置了一个全局标志。基本上,R 忽略了 结果的不可见性,无论如何都会打印它(FAQ 2.22)。[.data.tableinvisible()[.class
1赞 Matt Dowle 3/7/2013
因为在开发时(我只是source() .R 代码转换为 .GlobalEnv,本质上)我需要 9 岁。但是当安装软件包时,可以低得多 3.我认为这与包含 .data.tabledepthtriggerdepthtriggerByteCompile: TRUE
8赞 Matt Dowle 3/8/2013
@Spacedman 有时你必须打碎一些鸡蛋来做煎蛋,即使有几块蛋壳掉进去。
4赞 Jav 9/26/2016
在 v1.9.5 中引入的更新似乎不再在 v1.9.6(或今天的 1.9.7)中起作用。knitr 仍然在 := 赋值后打印 data.table。
1赞 João António 6/20/2014 #2

我遇到了同样的问题,通过重新分配变量,我相当容易地解决了它。就您而言:

DT <- DT[, ':=' (c, 5)]

不过,它有点冗长,特别是如果变量名称很大。

评论

0赞 DaveRGP 9/10/2015
这是我找到的最聪明的方法。特别是如果您不想更新到开发版本(因为当前的 cran 似乎是 v1.9.4)
7赞 Matt Pollock 8/20/2014 #3

为什么不直接使用:

```{r, results='hide'}
DT[, c:=5]
```

评论

1赞 Corvus 8/20/2014
因为它可能不是块中唯一的东西。随着变通方法的进行,自我分配可能会更好。最后,如果你的赋值调用了一个函数(代替了“5”),该函数会打印出来。
2赞 guest 5/9/2015 #4

只需用 invisible() 将表达式括起来即可。这对我有用。

评论

0赞 MichaelChirico 12/3/2016
这并不理想,因为如果输出被用作教程/参考,新学习者可能会被引导认为在常规编码中使用它是正常/必需的(事实并非如此)。不必要的混淆。echo = TRUEinvisible
5赞 DaveRGP 4/5/2017 #5

对于在 2017 年使用 RMarkdown 1.3 和 data.table 1.10 或类似版本返回此错误的任何人来说,此错误再次出现,如下所示 此处

随后在 RMarkdown 1.4 中修复了此问题