true - ¿Por qué falla el almacenamiento en caché de knitr para data.table `:=`?
n yihui name knitr (2)
Especulación:
Esto es lo que parece estar pasando.
Knitr guarda sensiblemente los objetos en cuanto se crean. A continuación, actualiza su valor almacenado en caché cada vez que detecta que se han modificado.
data.table , sin embargo, pasa por alto los mecanismos normales de asignación y reemplazo de copia por valor de R, y usa un operador :=
lugar de un =
, <<-
, o <-
. Como resultado, knitr no está captando las señales de que DT
ha cambiado DT[, c:=5]
.
Solución:
Simplemente agregue este bloque a su código donde desee que se vuelva a almacenar en caché el valor actual de DT
. No le costará nada de memoria o de tiempo (ya que nada excepto una referencia es copiada por DT <- DT
) pero envía efectivamente una señal (falsa) a Knitr que DT
se ha actualizado:
```{r, cache=TRUE, echo=FALSE}
DT <- DT
```
Versión de trabajo del documento de ejemplo:
Comprueba que funciona ejecutando esta versión editada de tu documento:
```{r}
library(data.table)
```
Data.Table Markdown
========================================================
Suppose we make a `data.table` in **R Markdown**
```{r, cache=TRUE}
DT = data.table(a = rnorm(10))
```
Then add a column using `:=`
```{r, cache=TRUE}
DT[, c:=5]
```
```{r, cache=TRUE, echo=FALSE}
DT <- DT
```
Then we display that in a non-cached block
```{r, cache=FALSE}
DT
```
The first time you run this, the above will show a `c` column.
The second, third, and nth times, it will as well.
Esto está relacionado en espíritu con this pregunta, pero debe ser diferente en el mecanismo.
Si intenta almacenar en caché un fragmento knitr
que contiene una data.table
:=
entonces actúa como si ese fragmento no se hubiera ejecutado y los fragmentos posteriores no vean el efecto de :=
.
¿Alguna idea de por qué esto es? ¿Cómo se han actualizado los objetos de detección de knitr
y qué hace data.table
que lo confunde?
Parece que puede solucionar esto haciendo DT = DT[, LHS:=RHS]
.
Ejemplo :
```{r}
library(data.table)
```
Data.Table Markdown
========================================================
Suppose we make a `data.table` in **R Markdown**
```{r, cache=TRUE}
DT = data.table(a = rnorm(10))
```
Then add a column using `:=`
```{r, cache=TRUE}
DT[, c:=5]
```
Then we display that in a non-cached block
```{r, cache=FALSE}
DT
```
The first time you run this, the above will show a `c` column,
from the second time onwards it will not.
Salida en segunda ejecución
Como se indica en el cuarto comentario bajo la respuesta de Josh O''Brien, agregué una nueva opción cache.vars
para manejar este caso tan especial. En el segundo fragmento almacenado en caché, podemos especificar cache.vars=''DT''
para que knitr
guarde una copia de DT
.
```{r}
library(data.table)
```
Data.Table Markdown
========================================================
Suppose we make a `data.table` in **R Markdown**
```{r, cache=TRUE}
DT = data.table(a = rnorm(10))
```
Then add a column using `:=`
```{r, cache=TRUE, cache.vars=''DT''}
DT[, c:=5]
```
Then we display that in a non-cached block
```{r, cache=FALSE}
DT
```
La salida es así, sin importar cuántas veces compile el documento: