Почему кэширование knitr терпит неудачу для data.table `: =`?
Это связано с духом с этим вопросом, но должно быть различным в механизме.
Если вы попытаетесь кэшировать фрагмент knitr
, который содержит назначение data.table
:=
, тогда он действует так, как будто этот фрагмент не был запущен, а более поздние фрагменты не видят влияния :=
.
Любая идея, почему это так? Как knitr
обнаруживает объекты, которые обновлены, а что data.table
делает это смущает?
Кажется, вы можете обойти это, выполнив DT = DT[, LHS:=RHS]
.
Пример:
```{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.
Выход во втором запуске
![knitr output]()
Ответы
Ответ 1
Спекуляция:
Вот что происходит.
knitr довольно разумно кэширует объекты, как только они создаются. Затем он обновляет свои кешированные значения, когда обнаруживает, что они были изменены.
data.table, однако, обходит R нормальные механизмы присваивания и замены по умолчанию и использует оператор :=
, а не =
, <<-
или <-
. В результате knitr не подбирает сигналы, которые DT
были изменены на DT[, c:=5]
.
Решение:
Просто добавьте этот блок в свой код, где бы вы не захотели повторно кэшировать текущее значение DT
. Это не будет стоить вам какой-либо памяти или по времени (поскольку ничего, кроме ссылки, не копируется с помощью DT <- DT
), но эффективно отправляет (поддельный) сигнал на knitr, который DT
был обновление:
```{r, cache=TRUE, echo=FALSE}
DT <- DT
```
Рабочая версия примера doc:
Убедитесь, что он работает, запустив эту отредактированную версию вашего документа:
```{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.
Ответ 2
Как указано в четвертом комментарии в ответе Джоша О'Брайена, я добавил новую опцию cache.vars
для обработки этого особого случая. Во втором кэшированном фрагменте мы можем указать cache.vars='DT'
, чтобы knitr
сохранил копию 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
```
Результат такой, независимо от того, сколько раз вы компилируете документ:
![knitr works with data.table now]()