When discussing performance with colleagues, teaching, sending a bug report or searching for guidance on mailing lists and here on SO, a reproducible example is often asked and always helpful.
What are your tips for creating an excellent example? How do you paste data structures from r in a text format? What other information should you include?
Are there other tricks in addition to using
A minimal reproducible example consists of the following items:
set.seed()) for reproducibility
Looking at the examples in the help files of the used functions is often helpful. In general, all the code given there fulfills the requirements of a minimal reproducible example: data is provided, minimal code is provided, and everything is runnable.
For most cases, this can be easily done by just providing a vector / data frame with some values. Or you can use one of the built-in datasets, which are provided with most packages.
A comprehensive list of built-in datasets can be seen with
library(help = "datasets"). There is a short description to every dataset and more information can be obtained for example with
?mtcars where 'mtcars' is one of the datasets in the list. Other packages might contain additional datasets.
Making a vector is easy. Sometimes it is necessary to add some randomness to it, and there are a whole number of functions to make that.
sample() can randomize a vector, or give a random vector with only a few values.
letters is a useful vector containing the alphabet. This can be used for making factors.
A few examples :
x <- rnorm(10)for normal distribution,
x <- runif(10)for uniform distribution, ...
x <- sample(1:10)for vector 1:10 in random order.
x <- sample(letters[1:4], 20, replace = TRUE)
For matrices, one can use
matrix(), eg :
matrix(1:10, ncol = 2)
Making data frames can be done using
data.frame(). One should pay attention to name the entries in the data frame, and to not make it overly complicated.
An example :
Data <- data.frame( X = sample(1:10), Y = sample(c("yes", "no"), 10, replace = TRUE) )
For some questions, specific formats can be needed. For these, one can use any of the provided
as.someType functions :
as.xts, ... These in combination with the vector and/or data frame tricks.
If you have some data that would be too difficult to construct using these tips, then you can always make a subset of your original data, using eg
subset() or the indices. Then use eg.
dput() to give us something that can be put in R immediately :
> dput(head(iris,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 = 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")
If your data frame has a factor with many levels, the
dput output can be unwieldy because it will still list all the possible factor levels even if they aren't present in the the subset of your data. To solve this issue, you can use the
droplevels() function. Notice below how species is a factor with only one level:
> dput(droplevels(head(iris, 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")
One other caveat for
dput is that it will not work for keyed
data.table objects or for grouped
dplyr. In these cases you can convert back to a regular data frame before sharing,
Worst case scenario, you can give a text representation that can be read in using the
text parameter of
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)
This should be the easy part but often isn't. What you should not do, is:
What you should do, is:
op <- par(mfrow=c(1,2)) ...some code... par(op))
In most cases, just the R version and the operating system will suffice. When conflicts arise with packages, giving the output of
sessionInfo() can really help. When talking about connections to other applications (be it through ODBC or anything else), one should also provide version numbers for those, and if possible also the necessary information on the setup.