Come creare un ottimo esempio riproducibile con R.

May 11 2011

Quando si discute delle prestazioni con i colleghi, si insegna, si invia una segnalazione di bug o si cerca una guida sulle mailing list e qui su Stack Overflow, viene spesso richiesto un esempio riproducibile e sempre utile.

Quali sono i tuoi consigli per creare un ottimo esempio? Come incollare le strutture dati da r in un formato di testo? Quali altre informazioni dovresti includere?

Ci sono altri trucchi oltre all'uso dput(), dump()o structure()? Quando dovresti includere library()o require()dichiarazioni? Che riservava parole dovrebbero evitare di uno, oltre a c, df, data, ecc?

Come si fa a fare un grande r esempio riproducibile?

Risposte

1756 JorisMeys May 11 2011 at 18:40

Un esempio riproducibile minimo è costituito dai seguenti elementi:

  • un set di dati minimo, necessario per dimostrare il problema
  • il codice eseguibile minimo necessario per riprodurre l'errore, che può essere eseguito sul set di dati specificato
  • le informazioni necessarie sui pacchetti utilizzati, la versione R e il sistema su cui viene eseguito.
  • nel caso di processi casuali, un seme (impostato da set.seed()) per la riproducibilità 1

Per esempi di buoni esempi riproducibili minimi , vedere i file della guida della funzione che si sta utilizzando. In generale, tutto il codice fornito soddisfa i requisiti di un esempio riproducibile minimo: vengono forniti i dati, viene fornito il codice minimo e tutto è eseguibile. Guarda anche le domande su Stack Overflow con molti voti positivi.

Produzione di un set di dati minimo

Nella maggior parte dei casi, ciò può essere fatto facilmente fornendo solo un vettore / frame di dati con alcuni valori. Oppure puoi utilizzare uno dei set di dati incorporati, forniti con la maggior parte dei pacchetti.
È possibile visualizzare un elenco completo di set di dati incorporati con library(help = "datasets"). C'è una breve descrizione per ogni set di dati e possono essere ottenute più informazioni, ad esempio, ?mtcarsdove "mtcars" è uno dei set di dati nell'elenco. Altri pacchetti potrebbero contenere set di dati aggiuntivi.

Creare un vettore è facile. A volte è necessario aggiungere un po 'di casualità e ci sono un numero intero di funzioni per farlo. sample()può randomizzare un vettore o dare un vettore casuale con solo pochi valori. lettersè un utile vettore contenente l'alfabeto. Questo può essere usato per creare fattori.

Alcuni esempi:

  • valori casuali: x <- rnorm(10)per distribuzione normale, x <- runif(10)per distribuzione uniforme, ...
  • una permutazione di alcuni valori: x <- sample(1:10)per il vettore 1:10 in ordine casuale.
  • un fattore casuale: x <- sample(letters[1:4], 20, replace = TRUE)

Per le matrici, si può usare matrix(), ad esempio:

matrix(1:10, ncol = 2)

La creazione di frame di dati può essere eseguita utilizzando data.frame(). Si dovrebbe prestare attenzione a nominare le voci nel frame di dati e a non renderlo eccessivamente complicato.

Un esempio :

set.seed(1)
Data <- data.frame(
    X = sample(1:10),
    Y = sample(c("yes", "no"), 10, replace = TRUE)
)

Per alcune domande possono essere necessari formati specifici. Per questi, si può usare qualsiasi delle previste as.someTypefunzioni: as.factor, as.Date, as.xts, ... Questi in combinazione con il vettore e / o della struttura dati trucchi.

Copia i tuoi dati

Se si dispone di alcuni dati che sarebbe troppo difficile da costruire con questi suggerimenti, allora si può sempre fare un sottoinsieme dei dati originali, utilizzando head(), subset()o gli indici. Quindi usa dput()per darci qualcosa che può essere messo immediatamente in R:

> dput(iris[1:4, ]) # first four rows of the iris data set
structure(list(Sepal.Length = c(5.1, 4.9, 4.7, 4.6), Sepal.Width = c(3.5, 
3, 3.2, 3.1), Petal.Length = c(1.4, 1.4, 1.3, 1.5), Petal.Width = c(0.2, 
0.2, 0.2, 0.2), Species = structure(c(1L, 1L, 1L, 1L), .Label = c("setosa", 
"versicolor", "virginica"), class = "factor")), .Names = c("Sepal.Length", 
"Sepal.Width", "Petal.Length", "Petal.Width", "Species"), row.names = c(NA, 
4L), class = "data.frame")

Se il data frame ha un fattore con molti livelli, l' dputoutput può essere ingombrante perché elencherà comunque tutti i possibili livelli di fattore anche se non sono presenti nel sottoinsieme dei dati. Per risolvere questo problema, puoi utilizzare la droplevels()funzione. Nota di seguito come la specie è un fattore con un solo livello:

> dput(droplevels(iris[1:4, ]))
structure(list(Sepal.Length = c(5.1, 4.9, 4.7, 4.6), Sepal.Width = c(3.5, 
3, 3.2, 3.1), Petal.Length = c(1.4, 1.4, 1.3, 1.5), Petal.Width = c(0.2, 
0.2, 0.2, 0.2), Species = structure(c(1L, 1L, 1L, 1L), .Label = "setosa",
class = "factor")), .Names = c("Sepal.Length", "Sepal.Width", 
"Petal.Length", "Petal.Width", "Species"), row.names = c(NA, 
4L), class = "data.frame")

Durante l'utilizzo dput, potresti anche voler includere solo le colonne pertinenti:

> dput(mtcars[1:3, c(2, 5, 6)]) # first three rows of columns 2, 5, and 6
structure(list(cyl = c(6, 6, 4), drat = c(3.9, 3.9, 3.85), wt = c(2.62, 
2.875, 2.32)), row.names = c("Mazda RX4", "Mazda RX4 Wag", "Datsun 710"
), class = "data.frame")

Un altro avvertimento dputè che non funzionerà per data.tableoggetti con chiave o per raggruppati tbl_df(classe grouped_df) da dplyr. In questi casi è possibile convertire di nuovo ad un frame di dati regolare prima condivisione, dput(as.data.frame(my_data)).

Nel peggiore dei casi, puoi fornire una rappresentazione testuale che può essere letta utilizzando il textparametro di read.table:

zz <- "Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa"

Data <- read.table(text=zz, header = TRUE)

Produzione di codice minimo

Questa dovrebbe essere la parte facile ma spesso non lo è. Quello che non dovresti fare è:

  • aggiungere tutti i tipi di conversioni di dati. Assicurati che i dati forniti siano già nel formato corretto (a meno che questo non sia il problema, ovviamente)
  • copia e incolla un'intera funzione / blocco di codice che restituisce un errore. Innanzitutto, prova a individuare esattamente le righe che provocano l'errore. Il più delle volte scoprirai qual è il problema da solo.

Quello che dovresti fare è:

  • aggiungi quali pacchetti dovrebbero essere usati se ne usi uno (usando library())
  • se apri connessioni o crei file, aggiungi del codice per chiuderle o eliminare i file (usando unlink())
  • se modifichi le opzioni, assicurati che il codice contenga un'istruzione per riportarle a quelle originali. (ad esempio op <- par(mfrow=c(1,2)) ...some code... par(op))
  • test eseguire il codice in una nuova sessione R vuota per assicurarsi che il codice sia eseguibile. Le persone dovrebbero essere in grado di copiare e incollare i tuoi dati e il tuo codice nella console e ottenere esattamente lo stesso che hai.

Fornisci informazioni aggiuntive

Nella maggior parte dei casi, saranno sufficienti solo la versione R e il sistema operativo. Quando sorgono conflitti con i pacchetti, fornire l'output di sessionInfo()può davvero aiutare. Quando si parla di connessioni ad altre applicazioni (sia tramite ODBC o qualsiasi altra cosa), è necessario fornire anche i numeri di versione per quelle e, se possibile, anche le informazioni necessarie sulla configurazione.

Se si esegue R in R Studio utilizzando rstudioapi::versionInfo()può essere utile a segnalare la versione RStudio.

Se hai un problema con un pacchetto specifico potresti voler fornire la versione del pacchetto dando l'output di packageVersion("name of the package").


1 Nota: l'output di è set.seed()diverso tra R> 3.6.0 e versioni precedenti. Specifica quale versione R hai utilizzato per il processo casuale e non sorprenderti se ottieni risultati leggermente diversi quando segui vecchie domande. Per ottenere lo stesso risultato in questi casi, puoi usare la funzione RNGversion()-prima set.seed()(es :) RNGversion("3.5.2").

595 hadley May 11 2011 at 20:57

(Ecco il mio consiglio da Come scrivere un esempio riproducibile . Ho provato a renderlo breve ma dolce)

Come scrivere un esempio riproducibile.

È molto probabile che tu riceva un buon aiuto con il tuo problema R se fornisci un esempio riproducibile. Un esempio riproducibile consente a qualcun altro di ricreare il tuo problema semplicemente copiando e incollando il codice R.

Ci sono quattro cose che devi includere per rendere riproducibile il tuo esempio: pacchetti richiesti, dati, codice e una descrizione del tuo ambiente R.

  • I pacchetti dovrebbero essere caricati all'inizio dello script, quindi è facile vedere di quali ha bisogno l'esempio.

  • Il modo più semplice per includere i dati in un'e-mail o in una domanda di overflow dello stack è utilizzare dput()per generare il codice R per ricrearlo. Ad esempio, per ricreare il mtcarsset di dati in R, eseguire i seguenti passaggi:

    1. Corri dput(mtcars)in R
    2. Copia l'output
    3. Nel mio script riproducibile, digita mtcars <-quindi incolla.
  • Dedica un po 'di tempo ad assicurarti che il tuo codice sia facile da leggere per gli altri:

    • assicurati di aver utilizzato gli spazi e che i nomi delle variabili siano concisi, ma informativi

    • usa i commenti per indicare dove si trova il tuo problema

    • fai del tuo meglio per rimuovere tutto ciò che non è correlato al problema.
      Più breve è il codice, più facile sarà da capire.

  • Includere l'output di sessionInfo()in un commento nel codice. Questo riepiloga il tuo ambiente R e semplifica il controllo se stai utilizzando un pacchetto obsoleto.

Puoi verificare di aver effettivamente creato un esempio riproducibile avviando una nuova sessione R e incollando lo script in.

Prima di inserire tutto il tuo codice in un'e-mail, considera di metterlo su Gist GitHub . Fornirà al tuo codice una buona evidenziazione della sintassi e non dovrai preoccuparti che nulla venga alterato dal sistema di posta elettronica.

307 RomanLuštrik May 11 2011 at 18:22

Personalmente, preferisco le battute "una". Qualcosa sulla falsariga:

my.df <- data.frame(col1 = sample(c(1,2), 10, replace = TRUE),
        col2 = as.factor(sample(10)), col3 = letters[1:10],
        col4 = sample(c(TRUE, FALSE), 10, replace = TRUE))
my.list <- list(list1 = my.df, list2 = my.df[3], list3 = letters)

La struttura dei dati dovrebbe imitare l'idea del problema dello scrittore e non l'esatta struttura testuale. Apprezzo molto quando le variabili non sovrascrivono le mie variabili o Dio non voglia, funzioni (come df).

In alternativa, è possibile tagliare alcuni angoli e indicare un set di dati preesistente, qualcosa come:

library(vegan)
data(varespec)
ord <- metaMDS(varespec)

Non dimenticare di menzionare eventuali pacchetti speciali che potresti utilizzare.

Se stai cercando di dimostrare qualcosa su oggetti più grandi, puoi provare

my.df2 <- data.frame(a = sample(10e6), b = sample(letters, 10e6, replace = TRUE))

Se stai lavorando con i dati spaziali tramite il rasterpacchetto, puoi generare alcuni dati casuali. Molti esempi possono essere trovati nella vignetta del pacchetto, ma ecco una piccola pepita.

library(raster)
r1 <- r2 <- r3 <- raster(nrow=10, ncol=10)
values(r1) <- runif(ncell(r1))
values(r2) <- runif(ncell(r2))
values(r3) <- runif(ncell(r3))
s <- stack(r1, r2, r3)

Se hai bisogno di un oggetto spaziale come implementato in sp, puoi ottenere alcuni set di dati tramite file esterni (come shapefile ESRI) in pacchetti "spaziali" (vedi la vista spaziale in Viste attività).

library(rgdal)
ogrDrivers()
dsn <- system.file("vectors", package = "rgdal")[1]
ogrListLayers(dsn)
ogrInfo(dsn=dsn, layer="cities")
cities <- readOGR(dsn=dsn, layer="cities")
281 RicardoSaporta May 14 2013 at 05:20

Ispirato proprio da questo post, ora utilizzo una comoda funzione
reproduce(<mydata>)quando devo pubblicare su StackOverflow.


ISTRUZIONI RAPIDE

Se myDataè il nome del tuo oggetto da riprodurre, esegui quanto segue in R:

install.packages("devtools")
library(devtools)
source_url("https://raw.github.com/rsaporta/pubR/gitbranch/reproduce.R")

reproduce(myData)

Dettagli:

Questa funzione è un wrapper intelligente dpute fa quanto segue:

  • campiona automaticamente un set di dati di grandi dimensioni (in base alle dimensioni e alla classe. La dimensione del campione può essere regolata)
  • crea un dputoutput
  • consente di specificare quali colonne esportare
  • si aggiunge alla parte anteriore in objName <- ...modo che possa essere facilmente copiato + incollato, ma ...
  • Se lavori su un Mac, l'output viene copiato automaticamente negli appunti, in modo che tu possa semplicemente eseguirlo e quindi incollarlo alla tua domanda.

La fonte è disponibile qui:

  • Github - pubR / riprodurre.R

Esempio:

# sample data
DF <- data.frame(id=rep(LETTERS, each=4)[1:100], replicate(100, sample(1001, 100)), Class=sample(c("Yes", "No"), 100, TRUE))

DF è di circa 100 x 102. Voglio campionare 10 righe e alcune colonne specifiche

reproduce(DF, cols=c("id", "X1", "X73", "Class"))  # I could also specify the column number. 

Fornisce il seguente output:

This is what the sample looks like: 

    id  X1 X73 Class
1    A 266 960   Yes
2    A 373 315    No            Notice the selection split 
3    A 573 208    No           (which can be turned off)
4    A 907 850   Yes
5    B 202  46   Yes         
6    B 895 969   Yes   <~~~ 70 % of selection is from the top rows
7    B 940 928    No
98   Y 371 171   Yes          
99   Y 733 364   Yes   <~~~ 30 % of selection is from the bottom rows.  
100  Y 546 641    No        


    ==X==============================================================X==
         Copy+Paste this part. (If on a Mac, it is already copied!)
    ==X==============================================================X==

 DF <- structure(list(id = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 25L, 25L, 25L), .Label = c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y"), class = "factor"), X1 = c(266L, 373L, 573L, 907L, 202L, 895L, 940L, 371L, 733L, 546L), X73 = c(960L, 315L, 208L, 850L, 46L, 969L, 928L, 171L, 364L, 641L), Class = structure(c(2L, 1L, 1L, 2L, 2L, 2L, 1L, 2L, 2L, 1L), .Label = c("No", "Yes"), class = "factor")), .Names = c("id", "X1", "X73", "Class"), class = "data.frame", row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 98L, 99L, 100L)) 

    ==X==============================================================X==

Si noti inoltre che l'intero output è in una bella riga singola, lunga, non un paragrafo alto di righe spezzettate. Ciò rende più facile leggere sui post di domande SO e anche più facile copiare + incollare.


Aggiornamento ottobre 2013:

È ora possibile specificare quante righe di testo verranno occupate (cioè cosa incollare in StackOverflow). Usa l' lines.out=nargomento per questo. Esempio:

reproduce(DF, cols=c(1:3, 17, 23), lines.out=7) rende:

    ==X==============================================================X==
         Copy+Paste this part. (If on a Mac, it is already copied!)
    ==X==============================================================X==

 DF <- structure(list(id = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 25L,25L, 25L), .Label
      = c("A", "B", "C", "D", "E", "F", "G", "H","I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U","V", "W", "X", "Y"), class = "factor"),
      X1 = c(809L, 81L, 862L,747L, 224L, 721L, 310L, 53L, 853L, 642L),
      X2 = c(926L, 409L,825L, 702L, 803L, 63L, 319L, 941L, 598L, 830L),
      X16 = c(447L,164L, 8L, 775L, 471L, 196L, 30L, 420L, 47L, 327L),
      X22 = c(335L,164L, 503L, 407L, 662L, 139L, 111L, 721L, 340L, 178L)), .Names = c("id","X1",
      "X2", "X16", "X22"), class = "data.frame", row.names = c(1L,2L, 3L, 4L, 5L, 6L, 7L, 98L, 99L, 100L))

    ==X==============================================================X==
198 SachaEpskamp May 11 2011 at 18:21

Ecco una buona guida .

Il punto più importante è: assicurati solo di creare un piccolo pezzo di codice che possiamo eseguire per vedere qual è il problema . Una funzione utile per questo è dput(), ma se hai dati molto grandi, potresti voler creare un piccolo set di dati di esempio o usare solo le prime 10 righe o giù di lì.

MODIFICARE:

Assicurati anche di aver identificato tu stesso dove si trova il problema. L'esempio non dovrebbe essere un intero script R con "Sulla riga 200 c'è un errore". Se usi gli strumenti di debug in R (I love browser()) e Google dovresti essere in grado di identificare davvero dove si trova il problema e riprodurre un esempio banale in cui la stessa cosa va storta.

167 RichieCotton May 11 2011 at 20:17

La mailing list di R-help ha una guida alla pubblicazione che copre sia le domande che le risposte, incluso un esempio di generazione di dati:

Esempi: a volte è utile fornire un piccolo esempio che qualcuno può effettivamente eseguire. Per esempio:

Se ho una matrice x come segue:

  > x <- matrix(1:8, nrow=4, ncol=2,
                dimnames=list(c("A","B","C","D"), c("x","y"))
  > x
    x y
  A 1 5
  B 2 6
  C 3 7
  D 4 8
  >

come posso trasformarlo in un dataframe con 8 righe e tre colonne denominate "row", "col" e "value", che hanno i nomi delle dimensioni come valori di "row" e "col", in questo modo:

  > x.df
     row col value
  1    A   x      1

...
(A cui la risposta potrebbe essere:

  > x.df <- reshape(data.frame(row=rownames(x), x), direction="long",
                    varying=list(colnames(x)), times=colnames(x),
                    v.names="value", timevar="col", idvar="row")

)

La parola piccolo è particolarmente importante. Dovresti mirare a un esempio riproducibile minimo , il che significa che i dati e il codice dovrebbero essere il più semplici possibile per spiegare il problema.

EDIT: il codice grazioso è più facile da leggere del codice brutto. Usa una guida di stile .

164 Paolo Jun 29 2012 at 15:32

Dalla R.2.14 (immagino) puoi fornire la rappresentazione del testo dei tuoi dati direttamente a read.table:

 df <- read.table(header=TRUE, 
  text="Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa
") 
146 BenBolker Jul 15 2011 at 02:49

A volte il problema non è davvero riproducibile con un dato più piccolo, non importa quanto ci provi, e non si verifica con dati sintetici (sebbene sia utile mostrare come hai prodotto set di dati sintetici che non hanno riprodotto il problema, perché esclude alcune ipotesi).

  • Potrebbe essere necessario pubblicare i dati sul Web da qualche parte e fornire un URL.
  • Se i dati non possono essere rilasciati al pubblico in generale, ma potrebbero essere condivisi del tutto, potresti essere in grado di offrirti di inviarli tramite posta elettronica alle parti interessate (sebbene ciò ridurrà il numero di persone che si preoccuperanno di lavorare su di essa).
  • In realtà non l'ho visto fare, perché le persone che non possono rilasciare i propri dati sono sensibili al rilascio di qualsiasi forma, ma sembrerebbe plausibile che in alcuni casi si possano ancora pubblicare dati se fossero sufficientemente anonimizzati / codificati / corrotti leggermente in qualche modo.

Se non puoi fare nessuno di questi, probabilmente devi assumere un consulente per risolvere il tuo problema ...

modifica : due utili domande SO per l'anonimizzazione / rimescolamento:

  • Come creare un set di dati di esempio da dati privati ​​(sostituendo nomi e livelli di variabili con segnaposto non informativi)?
  • Dato un insieme di numeri casuali tratti da una distribuzione univariata continua, trova la distribuzione
136 AriB.Friedman Jul 09 2012 at 22:41

Le risposte finora sono ovviamente ottime per la parte della riproducibilità. Questo è solo per chiarire che un esempio riproducibile non può e non deve essere l'unico componente di una domanda. Non dimenticare di spiegare come vuoi che sia e i contorni del tuo problema, non solo come hai tentato di arrivarci finora. Il codice non è sufficiente; hai bisogno anche di parole.

Ecco un esempio riproducibile di cosa evitare di fare (tratto da un esempio reale, nomi modificati per proteggere gli innocenti):


Di seguito sono riportati i dati di esempio e parte della funzione con cui ho problemi.

code
code
code
code
code (40 or so lines of it)

Come posso raggiungere questo obiettivo ?


124 jasmine_007 Feb 20 2014 at 16:11

Ho un modo molto semplice ed efficiente per creare un esempio R che non è stato menzionato sopra. In primo luogo puoi definire la tua struttura. Per esempio,

mydata <- data.frame(a=character(0), b=numeric(0),  c=numeric(0), d=numeric(0))

>fix(mydata)

Quindi puoi inserire i tuoi dati manualmente. Questo è efficiente per esempi più piccoli piuttosto che per quelli grandi.

119 JT85 Apr 10 2013 at 21:51

Per creare rapidamente uno dputdei tuoi dati puoi semplicemente copiare (una parte di) i dati negli appunti ed eseguire quanto segue in R:

per i dati in Excel:

dput(read.table("clipboard",sep="\t",header=TRUE))

per i dati in un file txt:

dput(read.table("clipboard",sep="",header=TRUE))

È possibile modificare sepin quest'ultimo se necessario. Questo funzionerà solo se i tuoi dati sono negli appunti, ovviamente.

118 BrodieG Feb 12 2015 at 22:24

Linee guida:


Il tuo obiettivo principale nell'elaborare le tue domande dovrebbe essere quello di rendere il più semplice possibile per i lettori capire e riprodurre il tuo problema sui loro sistemi. Fare così:

  1. Fornisci dati di input
  2. Fornire l'output previsto
  3. Spiega brevemente il tuo problema
    • se hai più di 20 righe di testo + codice puoi probabilmente tornare indietro e semplificare
    • semplificare il più possibile il codice preservando il problema / errore

Questo richiede un po 'di lavoro, ma sembra un giusto compromesso dal momento che stai chiedendo ad altri di lavorare per te.

Fornitura di dati:


Set di dati incorporati

L'opzione migliore è di gran lunga affidarsi a set di dati integrati. Questo rende molto facile per gli altri lavorare sul tuo problema. Digita data()al prompt R per vedere quali dati sono disponibili. Alcuni esempi classici:

  • iris
  • mtcars
  • ggplot2::diamonds (pacchetto esterno, ma quasi tutti ce l'hanno)

Esamina i set di dati integrati per trovarne uno adatto al tuo problema.

Se sei in grado di riformulare il tuo problema per utilizzare i set di dati incorporati, è molto più probabile che tu ottenga buone risposte (e voti positivi).

Dati autogenerati

Se il problema è molto specifico per un tipo di dati che non è rappresentato nei set di dati esistenti, fornire il codice R che genera il set di dati più piccolo possibile su cui si manifesta il problema. Per esempio

set.seed(1)  # important to make random data reproducible
myData <- data.frame(a=sample(letters[1:5], 20, rep=T), b=runif(20))

Ora qualcuno che cerca di rispondere alla mia domanda può copiare / incollare quelle due righe e iniziare a lavorare immediatamente sul problema.

dput

Come ultima risorsa , è possibile utilizzare dputper trasformare un oggetto dati in codice R (ad esempio dput(myData)). Dico come "ultima risorsa" perché l'output di dputè spesso piuttosto ingombrante, fastidioso da copiare e incollare e oscura il resto della domanda.

Fornire l'output previsto:


Qualcuno una volta ha detto:

Un'immagine dell'output previsto vale 1000 parole

- una persona molto saggia

Se puoi aggiungere qualcosa come "Mi aspettavo di ottenere questo risultato":

   cyl   mean.hp
1:   6 122.28571
2:   4  82.63636
3:   8 209.21429

alla tua domanda, è molto più probabile che le persone capiscano rapidamente cosa stai cercando di fare. Se il risultato atteso è ampio e poco maneggevole, probabilmente non hai pensato abbastanza a come semplificare il tuo problema (vedi dopo).

Spiega il tuo problema in modo succinto


La cosa principale da fare è semplificare il più possibile il problema prima di porre la domanda. Ri-inquadrare il problema per lavorare con i set di dati incorporati aiuterà molto a questo proposito. Scoprirai anche spesso che solo attraversando il processo di semplificazione risponderai al tuo problema.

Ecco alcuni esempi di buone domande:

  • con set di dati integrato
  • con i dati generati dagli utenti

In entrambi i casi, i problemi dell'utente quasi certamente non sono legati ai semplici esempi che forniscono. Piuttosto, hanno astratto la natura del loro problema e l'hanno applicata a un semplice set di dati per porre la loro domanda.

Perché ancora un'altra risposta a questa domanda?


Questa risposta si concentra su quella che penso sia la migliore pratica: usa set di dati incorporati e fornisci ciò che ti aspetti come risultato in una forma minima. Le risposte più importanti si concentrano su altri aspetti. Non mi aspetto che questa risposta raggiunga alcun rilievo; questo è qui solo in modo che possa collegarmi ad esso nei commenti alle domande dei principianti.

113 daniel Nov 27 2014 at 09:02

Il codice riproducibile è la chiave per ottenere aiuto. Tuttavia, ci sono molti utenti che potrebbero essere scettici sull'incollare anche solo una parte dei loro dati. Ad esempio, potrebbero lavorare con dati sensibili o su dati originali raccolti da utilizzare in un documento di ricerca. Per qualsiasi motivo, ho pensato che sarebbe stato bello avere una comoda funzione per "deformare" i miei dati prima di incollarli pubblicamente. La anonymizefunzione del pacchetto SciencesPoè molto sciocca, ma per me funziona bene con la dputfunzione.

install.packages("SciencesPo")

dt <- data.frame(
    Z = sample(LETTERS,10),
    X = sample(1:10),
    Y = sample(c("yes", "no"), 10, replace = TRUE)
)

> dt
   Z  X   Y
1  D  8  no
2  T  1 yes
3  J  7  no
4  K  6  no
5  U  2  no
6  A 10 yes
7  Y  5  no
8  M  9 yes
9  X  4 yes
10 Z  3  no

Quindi lo anonimo:

> anonymize(dt)
     Z    X  Y
1   b2  2.5 c1
2   b6 -4.5 c2
3   b3  1.5 c1
4   b4  0.5 c1
5   b7 -3.5 c1
6   b1  4.5 c2
7   b9 -0.5 c1
8   b5  3.5 c2
9   b8 -1.5 c2
10 b10 -2.5 c1

Si potrebbe anche voler campionare poche variabili invece di tutti i dati prima di applicare l'anonimizzazione e il comando dput.

    # sample two variables without replacement
> anonymize(sample.df(dt,5,vars=c("Y","X")))
   Y    X
1 a1 -0.4
2 a1  0.6
3 a2 -2.4
4 a1 -1.4
5 a2  3.6
102 userJT Feb 22 2013 at 22:29

Spesso hai bisogno di alcuni dati per un esempio, tuttavia, non vuoi pubblicare i tuoi dati esatti. Per utilizzare alcuni data.frame esistenti nella libreria stabilita, utilizzare il comando data per importarlo.

per esempio,

data(mtcars)

e poi risolvi il problema

names(mtcars)
your problem demostrated on the mtcars data set
92 TMS Jan 04 2014 at 02:07

Se disponi di un set di dati di grandi dimensioni che non può essere facilmente inserito nello script utilizzando dput(), pubblica i tuoi dati su pastebin e caricali utilizzando read.table:

d <- read.table("http://pastebin.com/raw.php?i=m1ZJuKLH")

Ispirato da @Henrik .

90 TylerRinker Jun 11 2015 at 20:57

Sto sviluppando il pacchetto Wakefield per rispondere a questa esigenza di condividere rapidamente dati riproducibili, a volte dputfunziona bene per set di dati più piccoli, ma molti dei problemi che affrontiamo sono molto più grandi, condividere un set di dati così grande tramite dputè impraticabile.

Di:

Wakefield consente all'utente di condividere un codice minimo per riprodurre i dati. L'utente impostan(numero di righe) e specifica un numero qualsiasi di funzioni variabili preimpostate (attualmente ce ne sono 70) che imitano i dati reali (cose come sesso, età, reddito ecc.)

Installazione:

Attualmente (2015-06-11), wakefield è un pacchetto GitHub ma andrà a CRAN alla fine dopo la scrittura degli unit test. Per installare rapidamente, usa:

if (!require("pacman")) install.packages("pacman")
pacman::p_load_gh("trinker/wakefield")

Esempio:

Ecco un esempio:

r_data_frame(
    n = 500,
    id,
    race,
    age,
    sex,
    hour,
    iq,
    height,
    died
)

Questo produce:

    ID  Race Age    Sex     Hour  IQ Height  Died
1  001 White  33   Male 00:00:00 104     74  TRUE
2  002 White  24   Male 00:00:00  78     69 FALSE
3  003 Asian  34 Female 00:00:00 113     66  TRUE
4  004 White  22   Male 00:00:00 124     73  TRUE
5  005 White  25 Female 00:00:00  95     72  TRUE
6  006 White  26 Female 00:00:00 104     69  TRUE
7  007 Black  30 Female 00:00:00 111     71 FALSE
8  008 Black  29 Female 00:00:00 100     64  TRUE
9  009 Asian  25   Male 00:30:00 106     70 FALSE
10 010 White  27   Male 00:30:00 121     68 FALSE
.. ...   ... ...    ...      ... ...    ...   ...
73 docendodiscimus Jan 09 2015 at 22:09

Se si dispone di una o più factorvariabili nei dati con cui si desidera renderli riproducibili dput(head(mydata)), considerare di aggiungerle droplevels, in modo che i livelli di fattori che non sono presenti nel set di dati ridotto a icona non siano inclusi dputnell'output, al fine di rendi l'esempio minimo :

dput(droplevels(head(mydata)))
66 CMichael Jan 09 2015 at 20:11

Mi chiedo se un file http://old.r-fiddle.org/link potrebbe essere un modo molto semplice per condividere un problema. Riceve un ID univoco simile e si potrebbe persino pensare di incorporarlo in SO.

49 user2100721 Jul 22 2016 at 17:01

Si prega di non incollare gli output della console in questo modo:

If I have a matrix x as follows:
> x <- matrix(1:8, nrow=4, ncol=2,
            dimnames=list(c("A","B","C","D"), c("x","y")))
> x
  x y
A 1 5
B 2 6
C 3 7
D 4 8
>

How can I turn it into a dataframe with 8 rows, and three
columns named `row`, `col`, and `value`, which have the
dimension names as the values of `row` and `col`, like this:
> x.df
    row col value
1    A   x      1
...
(To which the answer might be:
> x.df <- reshape(data.frame(row=rownames(x), x), direction="long",
+                varying=list(colnames(x)), times=colnames(x),
+                v.names="value", timevar="col", idvar="row")
)

Non possiamo copiarlo e incollarlo direttamente.

Per rendere le domande e le risposte correttamente riproducibili, prova a rimuovere +& >prima di pubblicarlo e a inserire #output e commenti in questo modo:

#If I have a matrix x as follows:
x <- matrix(1:8, nrow=4, ncol=2,
            dimnames=list(c("A","B","C","D"), c("x","y")))
x
#  x y
#A 1 5
#B 2 6
#C 3 7
#D 4 8

# How can I turn it into a dataframe with 8 rows, and three
# columns named `row`, `col`, and `value`, which have the
# dimension names as the values of `row` and `col`, like this:

#x.df
#    row col value
#1    A   x      1
#...
#To which the answer might be:

x.df <- reshape(data.frame(row=rownames(x), x), direction="long",
                varying=list(colnames(x)), times=colnames(x),
                v.names="value", timevar="col", idvar="row")

Un'altra cosa, se hai usato una funzione da un certo pacchetto, menziona quella libreria.

34 andrii Aug 19 2017 at 02:02

Puoi farlo usando reprex .

Come ha notato mt1022 , "... un buon pacchetto per produrre esempi minimi e riproducibili è " reprex " di tidyverse ".

Secondo Tidyverse :

L'obiettivo di "reprex" è impacchettare il codice problematico in modo tale che altre persone possano eseguirlo e sentire il tuo dolore.

Un esempio è fornito sul sito web di tidyverse .

library(reprex)
y <- 1:4
mean(y)
reprex() 

Penso che questo sia il modo più semplice per creare un esempio riproducibile.

33 5revs,2users84%user5947301 Apr 20 2016 at 17:50

A parte tutte le risposte sopra che ho trovato molto interessanti, a volte potrebbe essere molto facile come discusso qui: - COME FARE UN ESEMPIO MINIMO RIPRODUCIBILE PER OTTENERE AIUTO CON R

Esistono molti modi per creare un vettore casuale Crea un vettore di 100 numeri con valori casuali in R arrotondati a 2 decimali o una matrice casuale in R

mydf1<- matrix(rnorm(20),nrow=20,ncol=5)

Si noti che a volte è molto difficile condividere un dato dato a causa di vari motivi come la dimensione ecc. Tuttavia, tutte le risposte di cui sopra sono ottime e molto importanti da pensare e utilizzare quando si vuole fare un esempio di dati riproducibile. Ma si noti che per rendere un dato rappresentativo dell'originale (nel caso in cui l'OP non possa condividere i dati originali), è bene aggiungere alcune informazioni con l'esempio di dati come (se chiamiamo i dati mydf1)

class(mydf1)
# this shows the type of the data you have 
dim(mydf1)
# this shows the dimension of your data

Inoltre, si dovrebbe conoscere il tipo, la lunghezza e gli attributi di un dato che può essere una struttura di dati

#found based on the following 
typeof(mydf1), what it is.
length(mydf1), how many elements it contains.
attributes(mydf1), additional arbitrary metadata.

#If you cannot share your original data, you can str it and give an idea about the structure of your data
head(str(mydf1))
28 TheRimalaya Apr 10 2016 at 01:15

Ecco alcuni dei miei suggerimenti:

  • Prova a utilizzare i set di dati R predefiniti
  • Se hai il tuo set di dati, includili con dput, in modo che altri possano aiutarti più facilmente
  • Non usare a install.package()meno che non sia veramente necessario, le persone capiranno se usi solo requireolibrary
  • Cerca di essere conciso,

    • Avere un set di dati
    • Prova a descrivere l'output di cui hai bisogno nel modo più semplice possibile
    • Fallo da solo prima di porre la domanda
  • È facile caricare un'immagine, quindi carica i grafici se lo hai
  • Includere anche eventuali errori che potresti avere

Tutti questi fanno parte di un esempio riproducibile.

18 dank Apr 05 2017 at 04:08

È una buona idea usare le funzioni del testthatpacchetto per mostrare cosa ci si aspetta che accada. Pertanto, altre persone possono modificare il codice finché non viene eseguito senza errori. Questo allevia il peso di coloro che vorrebbero aiutarti, perché significa che non devono decodificare la tua descrizione testuale. Per esempio

library(testthat)
# code defining x and y
if (y >= 10) {
    expect_equal(x, 1.23)
} else {
    expect_equal(x, 3.21)
}

è più chiaro di "Penso che x risulterebbe essere 1,23 per y uguale o superiore a 10 e 3,21 altrimenti, ma non ho ottenuto nessuno dei due risultati". Anche in questo stupido esempio, penso che il codice sia più chiaro delle parole. L'utilizzo testthatconsente al tuo aiutante di concentrarsi sul codice, il che fa risparmiare tempo e fornisce loro un modo per sapere che hanno risolto il tuo problema, prima di pubblicarlo