2015-10-21 15 views
9

Obiettivo

Voglio creare la mia analisi dei dati riproducibile facendo in modo che i blocchi dipendano da tutti i blocchi precedenti. Quindi, se ci sono 3 blocchi e io cambio qualcosa nel 1 ° blocco, i successivi 2 blocchi dovrebbero essere ripetuti in modo che riflettano la modifica apportata alle uscite. Voglio aggiungere questa condizione nelle opzioni globali del blocco nella parte superiore del documento, in modo da non dover utilizzare più volte lo dependson.Come rendere i pezzi di codice dipendono da tutti i blocchi precedenti in knitr/rmarkdown?

Problemi

Le uscite di un pezzo non cambiano se non viene modificato e cache=TRUE. Per i pezzi che contengono il codice, che può renderli affidabili su tutti i precedenti utilizzando seguito nella parte superiore del documento:

```{r setup, echo=FALSE} 
# set global chunk options: 
library(knitr) 
opts_chunk$set(cache=TRUE, autodep = TRUE) 
dep_auto() 
``` 

Se uno dei pezzi di cui sopra è cambiato, tutti pezzi successivi sono re-run. Ma questo non funziona se uso source() in blocchi per leggere gli script R. Di seguito è riportato un documento di esempio:

--- 
title: "Untitled" 
output: html_document 
--- 
```{r setup, echo=FALSE} 
# set global chunk options: 
library(knitr) 
opts_chunk$set(cache=TRUE, autodep = TRUE) 
dep_auto() 
``` 


# Create Data 
```{r} 
#source("data1.R") 
x <- data.frame(col1 = 4:10, col2 = 6:12) 
x 
``` 

# Summaries 
```{r} 
#source("data2.R") 

median1.of.x <- sapply(x, function(x) median(x)-1) 

sd.of.x <- sapply(x, sd) 

plus.of.x <- sapply(x, function(x) mean(x)+1) 

jj <- rbind(plus.of.x, sd.of.x, median1.of.x) 

``` 

```{r} 
jj 
``` 

Ora, se cambio uno qualsiasi dei 1 ° 2 pezzi il terzo pezzo dà uscita corretta dopo knit ting. Ma se invece inserisco il primo codice del blocco in un file sorgente data1.R e il secondo pezzo nel file data2.R, mantenendo le opzioni globali del blocco come prima, se apporto delle modifiche nei file di origine non si riflettono correttamente nell'output del terzo blocco. Ad esempio, la modifica x-x <- data.frame(col1 = 5:11, col2 = 6:12) dovrebbe cedere:

> jj 
       col1  col2 
plus.of.x 9.000000 10.000000 
sd.of.x  2.160247 2.160247 
median1.of.x 8.000000 9.000000 

Ma con l'uso di source() come discusso in precedenza, i rapporti knitr documento:

jj 
##    col1  col2 
## mean.of.x 5.000000 9.000000 
## sd.of.x 2.160247 2.160247 
## minus.of.x 6.000000 10.000000 

Quali impostazioni devo cambiare per usare source in knitr documenti correttamente?

+0

quando si utilizza il metodo 'fonte fissa, si sta commentando la x <' - data.frame) 'linea (, giusto? – rawr

+1

Knitr non è molto adatto per il tipo di flusso di lavoro dichiarativo di cui hai bisogno per farlo accadere. Consiglierei make & makefiles, o se vuoi rimanere completamente all'interno di R, l'eccellente [pacchetto remake] (https://github.com/richfitz/remake) – Ben

+0

@rawr Sì, tengo solo il comando 'source' e commenta tutti gli altri. –

risposta

12

Quando si utilizza source(), knitr non è possibile analizzare i possibili oggetti da creare da esso; knitr deve essere in grado di vedere il codice sorgente completo per analizzare le dipendenze tra i blocchi di codice.Ci sono due approcci per risolvere il problema:

  1. Dillo al secondo pezzo che dipende dal valore di x con l'aggiunta di un'opzione pezzo arbitrario che utilizza il valore della x, per esempio ```{r cache.extra = x}; quindi ogni volta che cambia x, la cache di questo blocco di codice verrà automaticamente invalidata (more info);
  2. Let knitr vedere il codice sorgente completo; puoi passare il codice sorgente a un chunk di codice tramite l'opzione chunk code, ad es. ```{r code = readLines('data1.R')} (uguale per data2.R); quindi dep_auto() dovrebbe essere in grado di capire che x è stato creato dal primo blocco e utilizzato nel secondo blocco, quindi il secondo blocco deve dipendere dal primo blocco.
+0

Grazie mille, Yihui. In generale, quale sarebbe il tuo consiglio per avvicinarti a un progetto di analisi dei dati? Sta usando 'source' consigliato per raccogliere/creare dati? –

+1

Un terzo approccio potrebbe usare 'read_chunk ('data1.R')', seguendo [esempio 113] (https://github.com/yihui/knitr-examples/blob/master/113-externalization.Rmd)? – Ben

+2

@umairdurrani Non ho un consiglio generale qui, ma se vuoi mettere qualche codice R in script R separati, puoi usare l'opzione 'code' che ho menzionato, o' read_chunk() 'come menzionato @Ben devono etichettare i pezzi del codice). 'source()' va bene in generale, e non riesco a pensare ad altri casi in cui può essere problematico. –

0

Penso che, per impostazione predefinita, i blocchi dipendono dai blocchi precedenti e l'autore ha fatto di tutto per cercare di far iniziare ogni blocco con lo stesso ambiente terminato l'ultimo (anche se ci sono numerosi modi per avvitare questo , come ad esempio il sourcing di file con la memorizzazione nella cache attivata ...) Non riesco a ricordare la sintassi, ma puoi includere pezzi di knitr in documenti esterni. C'è anche un trucco per riutilizzare i pezzi di knitr nello stesso documento in un modo simile alla funzione riutilizzando l'etichetta, e potresti essere in grado di creare una dipendenza non lineare da questo. Ma perché non impostare la cache su FALSE quando non si desidera eseguire il caching? L'approvvigionamento sembra una cattiva idea, ma non riesco a capire perché. Vorrei rendere lineare il flusso di lavoro di knitr e inserire la logica nelle funzioni, e disattivare il caching se la stessa chiamata di funzione può restituire cose diverse con gli stessi parametri di input.

Un altro trucco che potrebbe esserti utile è la capacità aggiunta di recente di creare un documento utilizzando i parametri di input. Questo potrebbe estrarre qualche logica dal tuo knitr doc, che credo sia la radice evitabile dei tuoi problemi.

+0

'cache = FALSE' è ok per questo esempio, ma per i blocchi intensamente computazionalmente è una pessima idea. L'uso di 'source' è utile se si desidera utilizzare lo stesso blocco in più documenti. L'esternalizzazione del codice in knitr è possibile ma richiede l'uso di tutti i blocchi che sono interdipendenti. Ecco perché 'source' è una scelta migliore. Forse la fase di lettura dei dati dovrebbe essere esplicitamente definita nel primo blocco. –

+1

Immagino che l'altra opzione stia usando un diverso meccanismo di memorizzazione nella cache. Mi piace R.cache. So che ci si sente come se knitr fosse in grado di fare ciò che si desidera, ma, avendo fatto tutto da solo, ho trovato che era meglio mantenere il knitr doc molto semplice e ottenere la logica in un vero linguaggio di programmazione, ad esempio R! –

0

ho scoperto che questo funziona (knitr 1.17):

<<..., dependson=all_labels()>>= 
... 
@ 
Problemi correlati