How to make a great R reproducible example?
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 dput()
, dump()
or structure()
? When should you include library()
or require()
statements? Which reserved words should one avoid, in addition to c
, df
, data
, etc?
How does one make a great r reproducible example?
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.
Producing a minimal dataset
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.factor
, as.Date
, as.xts
, ... These in combination with the vector and/or data frame tricks.
Copy your data
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 head()
, 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 tbl_df
(class grouped_df
) from dplyr
. In these cases you can convert back to a regular data frame before sharing, dput(as.data.frame(my_data))
.
Worst case scenario, you can give a text representation that can be read in using the text
parameter of 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)
Producing minimal code
This should be the easy part but often isn't. What you should not do, is:
What you should do, is:
unlink()
) op <- par(mfrow=c(1,2)) ...some code... par(op)
) Give extra information
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.
If you are running R in R Studio using rstudioapi::versionInfo()
can be helpful to report your RStudio version.
If you have a problem with a specific package you may want to provide the version of the package by giving the output of packageVersion("name of the package")
.
(Here's my advice from How to write a reproducible example . I've tried to make it short but sweet)
How to write a reproducible example.
You are most likely to get good help with your R problem if you provide a reproducible example. A reproducible example allows someone else to recreate your problem by just copying and pasting R code.
There are four things you need to include to make your example reproducible: required packages, data, code, and a description of your R environment.
Packages should be loaded at the top of the script, so it's easy to see which ones the example needs.
The easiest way to include data in an email or Stack Overflow question is to use dput()
to generate the R code to recreate it. For example, to recreate the mtcars
dataset in R, I'd perform the following steps:
dput(mtcars)
in R mtcars <-
then paste. Spend a little bit of time ensuring that your code is easy for others to read:
make sure you've used spaces and your variable names are concise, but informative
use comments to indicate where your problem lies
do your best to remove everything that is not related to the problem.
The shorter your code is, the easier it is to understand.
Include the output of sessionInfo()
in a comment in your code. This summarises your R environment and makes it easy to check if you're using an out-of-date package.
You can check you have actually made a reproducible example by starting up a fresh R session and pasting your script in.
Before putting all of your code in an email, consider putting it on Gist github . It will give your code nice syntax highlighting, and you don't have to worry about anything getting mangled by the email system.
Personally, I prefer "one" liners. Something along the lines:
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)
The data structure should mimic the idea of writer's problem and not the exact verbatim structure. I really appreciate it when variables don't overwrite my own variables or god forbid, functions (like df
).
Alternatively, one could cut a few corners and point to a pre-existing data set, something like:
library(vegan)
data(varespec)
ord <- metaMDS(varespec)
Don't forget to mention any special packages you might be using.
If you're trying to demonstrate something on larger objects, you can try
my.df2 <- data.frame(a = sample(10e6), b = sample(letters, 10e6, replace = TRUE))
If you're working with spatial data via the raster
package, you can generate some random data. A lot of examples can be found in the package vignette, but here's a small nugget.
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)
If you're in need of some spatial object as implemented in sp
, you can get some datasets via external files (like ESRI shapefile) in "spatial" packages (see the Spatial view in Task Views).
library(rgdal)
ogrDrivers()
dsn <- system.file("vectors", package = "rgdal")[1]
ogrListLayers(dsn)
ogrInfo(dsn=dsn, layer="cities")
cities <- readOGR(dsn=dsn, layer="cities")
链接地址: http://www.djcxy.com/p/624.html
上一篇: 我应该在MySQL中使用日期时间或时间戳数据类型吗?
下一篇: 如何做一个伟大的R可重现的例子?