Cómo hacer un gran ejemplo reproducible de R
Cuando se habla de rendimiento con colegas, se enseña, se envía un informe de error o se busca orientación en listas de correo y aquí en Stack Overflow, a menudo se pide un ejemplo reproducible y siempre es útil.
¿Cuáles son sus consejos para crear un ejemplo excelente? ¿Cómo se pegan las estructuras de datos de r en formato de texto? ¿Qué otra información debería incluir?
¿Hay otros trucos además de usar dput()
, dump()
o structure()
? ¿Cuándo debe incluir declaraciones library()
o require()
? ¿Qué palabras reservadas debe uno evitar, además c
, df
, data
, etc.?
¿Cómo hacer un gran r ejemplo reproducible?
Respuestas
Un ejemplo mínimo reproducible consta de los siguientes elementos:
- un conjunto de datos mínimo, necesario para demostrar el problema
- el código ejecutable mínimo necesario para reproducir el error, que se puede ejecutar en el conjunto de datos dado
- la información necesaria sobre los paquetes utilizados, la versión R y el sistema en el que se ejecuta.
- en el caso de procesos aleatorios, una semilla (establecida por
set.seed()
) para la reproducibilidad 1
Para obtener ejemplos de buenos ejemplos mínimos reproducibles , consulte los archivos de ayuda de la función que está utilizando. En general, todo el código que se proporciona allí cumple los requisitos de un ejemplo mínimo reproducible: se proporcionan datos, se proporciona un código mínimo y todo es ejecutable. También mire las preguntas en Stack Overflow con muchos votos a favor.
Producir un conjunto de datos mínimo
En la mayoría de los casos, esto se puede hacer fácilmente simplemente proporcionando un vector / marco de datos con algunos valores. O puede utilizar uno de los conjuntos de datos integrados, que se proporcionan con la mayoría de los paquetes.
Se puede ver una lista completa de conjuntos de datos integrados library(help = "datasets")
. Hay una breve descripción de cada conjunto de datos y se puede obtener más información, por ejemplo, ?mtcars
donde 'mtcars' es uno de los conjuntos de datos en la lista. Otros paquetes pueden contener conjuntos de datos adicionales.
Hacer un vector es fácil. A veces es necesario agregarle algo de aleatoriedad, y hay una gran cantidad de funciones para hacer eso. sample()
puede aleatorizar un vector o dar un vector aleatorio con solo unos pocos valores. letters
es un vector útil que contiene el alfabeto. Esto se puede usar para hacer factores.
Algunos ejemplos :
- valores aleatorios:
x <- rnorm(10)
para distribución normal,x <- runif(10)
para distribución uniforme, ... - una permutación de algunos valores:
x <- sample(1:10)
para el vector 1:10 en orden aleatorio. - un factor aleatorio:
x <- sample(letters[1:4], 20, replace = TRUE)
Para matrices, se puede utilizar matrix()
, por ejemplo:
matrix(1:10, ncol = 2)
La creación de marcos de datos se puede hacer usando data.frame()
. Se debe prestar atención a nombrar las entradas en el marco de datos y no hacerlo demasiado complicado.
Un ejemplo :
set.seed(1)
Data <- data.frame(
X = sample(1:10),
Y = sample(c("yes", "no"), 10, replace = TRUE)
)
Para algunas preguntas, se pueden necesitar formatos específicos. Para estos, uno puede utilizar cualquiera de los previstos as.someType
funciones: as.factor
, as.Date
, as.xts
, ... Estos en combinación con los trucos de vectores y / o trama de datos.
Copie sus datos
Si usted tiene algunos datos que serían demasiado difíciles de construir uso de estos consejos, entonces siempre se puede hacer un subconjunto de los datos originales, utilizando head()
, subset()
o los índices. Luego use dput()
para darnos algo que se pueda poner en R inmediatamente:
> 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")
Si su marco de datos tiene un factor con muchos niveles, la dput
salida puede ser difícil de manejar porque aún enumerará todos los niveles de factor posibles incluso si no están presentes en el subconjunto de sus datos. Para resolver este problema, puede utilizar la droplevels()
función. Observe a continuación cómo la especie es un factor con un solo nivel:
> 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")
Al usar dput
, es posible que también desee incluir solo columnas relevantes:
> 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")
Otra advertencia dput
es que no funcionará para data.table
objetos con clave o agrupados tbl_df
(clase grouped_df
) desde dplyr
. En estos casos se puede convertir de nuevo a una trama de datos regular antes de compartir dput(as.data.frame(my_data))
.
En el peor de los casos, puede dar una representación de texto que se pueda leer usando el text
parámetro de 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)
Produciendo código mínimo
Esta debería ser la parte fácil, pero a menudo no lo es. Lo que no debes hacer es:
- agregue todo tipo de conversiones de datos. Asegúrese de que los datos proporcionados ya estén en el formato correcto (a menos que ese sea el problema, por supuesto)
- copiar y pegar una función / fragmento de código completo que da un error. Primero, intente localizar qué líneas dan exactamente como resultado el error. La mayoría de las veces, usted mismo descubrirá cuál es el problema.
Lo que debes hacer es:
- agregue qué paquetes deben usarse si usa alguno (usando
library()
) - si abre conexiones o crea archivos, agregue algún código para cerrarlos o eliminar los archivos (usando
unlink()
) - si cambia las opciones, asegúrese de que el código contenga una declaración para revertirlas a las originales. (por ejemplo
op <- par(mfrow=c(1,2)) ...some code... par(op)
) - pruebe, ejecute su código en una nueva sesión de R vacía para asegurarse de que el código sea ejecutable. La gente debería poder simplemente copiar y pegar sus datos y su código en la consola y obtener exactamente lo mismo que usted.
Dar información extra
En la mayoría de los casos, bastará con la versión R y el sistema operativo. Cuando surgen conflictos con los paquetes, dar el resultado de sessionInfo()
puede ser de gran ayuda. Cuando se habla de conexiones a otras aplicaciones (ya sea a través de ODBC o cualquier otra cosa), también se deben proporcionar los números de versión de esas y, si es posible, también la información necesaria sobre la configuración.
Si está ejecutando R en R Studio usando rstudioapi::versionInfo()
puede ser útil para reportar su versión rstudio.
Si tiene un problema con un paquete específico, es posible que desee proporcionar la versión del paquete dando el resultado de packageVersion("name of the package")
.
1 Nota: La salida de set.seed()
difiere entre R> 3.6.0 y versiones anteriores. Especifique qué versión de R usó para el proceso aleatorio y no se sorprenda si obtiene resultados ligeramente diferentes al seguir preguntas anteriores. Para obtener el mismo resultado en tales casos, puede usar la RNGversion()
función-antes set.seed()
(por ejemplo :) RNGversion("3.5.2")
.
(Aquí está mi consejo de Cómo escribir un ejemplo reproducible . He intentado que sea breve pero agradable)
Cómo escribir un ejemplo reproducible.
Es más probable que obtenga una buena ayuda con su problema de R si proporciona un ejemplo reproducible. Un ejemplo reproducible le permite a otra persona recrear su problema simplemente copiando y pegando código R.
Hay cuatro cosas que debe incluir para que su ejemplo sea reproducible: paquetes requeridos, datos, código y una descripción de su entorno R.
Los paquetes deben cargarse en la parte superior del script, por lo que es fácil ver cuáles necesita el ejemplo.
La forma más fácil de incluir datos en un correo electrónico o una pregunta de desbordamiento de pila es usar
dput()
para generar el código R para recrearlo. Por ejemplo, para recrear elmtcars
conjunto de datos en R, realizaría los siguientes pasos:- Ejecutar
dput(mtcars)
en R - Copiar la salida
- En mi secuencia de comandos reproducible, escriba y
mtcars <-
luego pegue.
- Ejecutar
Dedique un poco de tiempo a asegurarse de que su código sea fácil de leer para otros:
asegúrese de haber utilizado espacios y que los nombres de las variables sean concisos, pero informativos
use comentarios para indicar dónde radica su problema
haga todo lo posible para eliminar todo lo que no esté relacionado con el problema.
Cuanto más corto sea su código, más fácil será de entender.
Incluya la salida de
sessionInfo()
en un comentario en su código. Esto resume su entorno de R y facilita la verificación si está utilizando un paquete desactualizado.
Puede comprobar que ha creado un ejemplo reproducible iniciando una nueva sesión de R y pegando su script en formato.
Antes de poner todo su código en un correo electrónico, considere ponerlo en Gist github . Le dará a su código un buen resaltado de sintaxis, y no tiene que preocuparse de que el sistema de correo electrónico estropee nada.
Personalmente, prefiero los revestimientos "uno". Algo parecido a esto:
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 estructura de datos debe imitar la idea del problema del escritor y no la estructura literal exacta. Realmente aprecio cuando las variables no sobrescriben mis propias variables o Dios no lo quiera, funciones (como df
).
Alternativamente, uno podría cortar algunas esquinas y apuntar a un conjunto de datos preexistente, algo como:
library(vegan)
data(varespec)
ord <- metaMDS(varespec)
No olvide mencionar los paquetes especiales que pueda estar utilizando.
Si está intentando demostrar algo en objetos más grandes, puede intentar
my.df2 <- data.frame(a = sample(10e6), b = sample(letters, 10e6, replace = TRUE))
Si está trabajando con datos espaciales a través del raster
paquete, puede generar algunos datos aleatorios. Se pueden encontrar muchos ejemplos en la viñeta del paquete, pero aquí hay una pequeña 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)
Si necesita algún objeto espacial implementado en sp
, puede obtener algunos conjuntos de datos a través de archivos externos (como el shapefile ESRI) en paquetes "espaciales" (consulte la Vista espacial en Vistas de tareas).
library(rgdal)
ogrDrivers()
dsn <- system.file("vectors", package = "rgdal")[1]
ogrListLayers(dsn)
ogrInfo(dsn=dsn, layer="cities")
cities <- readOGR(dsn=dsn, layer="cities")
Inspirado por esta misma publicación, ahora uso una función útil
reproduce(<mydata>)
cuando necesito publicar en StackOverflow.
INSTRUCCIONES RÁPIDAS
Si myData
es el nombre de su objeto para reproducir, ejecute lo siguiente en R:
install.packages("devtools")
library(devtools)
source_url("https://raw.github.com/rsaporta/pubR/gitbranch/reproduce.R")
reproduce(myData)
Detalles:
Esta función es una envoltura inteligente dput
y hace lo siguiente:
- muestrea automáticamente un gran conjunto de datos (según el tamaño y la clase. El tamaño de la muestra se puede ajustar)
- crea una
dput
salida - le permite especificar qué columnas exportar
- se agrega al frente
objName <- ...
para que se pueda copiar y pegar fácilmente, pero ... - Si trabaja en una Mac, la salida se copia automáticamente en el portapapeles, de modo que simplemente puede ejecutarla y luego pegarla en su pregunta.
La fuente está disponible aquí:
- Github - pubR / reproduce.R
Ejemplo:
# 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 es de aproximadamente 100 x 102. Quiero muestrear 10 filas y algunas columnas específicas
reproduce(DF, cols=c("id", "X1", "X73", "Class")) # I could also specify the column number.
Da el siguiente resultado:
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==
Tenga en cuenta también que la totalidad de la salida está en una bonita línea única y larga, no en un párrafo alto de líneas cortadas. Esto hace que sea más fácil de leer en las publicaciones de preguntas SO y también más fácil de copiar y pegar.
Actualización de octubre de 2013:
Ahora puede especificar cuántas líneas de salida de texto ocupará (es decir, qué pegará en StackOverflow). Usa el lines.out=n
argumento para esto. Ejemplo:
reproduce(DF, cols=c(1:3, 17, 23), lines.out=7)
rinde:
==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==
He aquí una buena guía .
El punto más importante es: solo asegúrese de hacer un pequeño fragmento de código que podamos ejecutar para ver cuál es el problema . Una función útil para esto es dput()
, pero si tiene datos muy grandes, es posible que desee crear un pequeño conjunto de datos de muestra o solo usar las primeras 10 líneas más o menos.
EDITAR:
También asegúrese de identificar usted mismo dónde está el problema. El ejemplo no debe ser un script R completo con "En la línea 200 hay un error". Si usa las herramientas de depuración en R (me encanta browser()
) y Google, debería poder identificar realmente dónde está el problema y reproducir un ejemplo trivial en el que lo mismo sale mal.
La lista de correo de R-help tiene una guía de publicación que cubre tanto la realización de preguntas como la respuesta, incluido un ejemplo de generación de datos:
Ejemplos: a veces es útil proporcionar un pequeño ejemplo de que alguien realmente puede ejecutar. Por ejemplo:
Si tengo una matriz x de la siguiente manera:
> 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
>
¿Cómo puedo convertirlo en un marco de datos con 8 filas y tres columnas llamadas 'fila', 'col' y 'valor', que tienen los nombres de dimensión como los valores de 'fila' y 'col', así:
> x.df
row col value
1 A x 1
...
(A lo que la respuesta podría ser:
> 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 palabra pequeño es especialmente importante. Debe apuntar a un ejemplo mínimo reproducible, lo que significa que los datos y el código deben ser lo más simples posible para explicar el problema.
EDITAR: El código bonito es más fácil de leer que el código feo. Utilice una guía de estilo .
Desde R.2.14 (supongo) puede alimentar su representación de texto de datos directamente 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
")
A veces, el problema realmente no se puede reproducir con un fragmento de datos más pequeño, sin importar cuánto lo intente, y no ocurre con datos sintéticos (aunque es útil mostrar cómo produjo conjuntos de datos sintéticos que no reprodujeron el problema, porque descarta algunas hipótesis).
- Puede ser necesario publicar los datos en la web en algún lugar y proporcionar una URL.
- Si los datos no se pueden divulgar al público en general, pero podrían compartirse, entonces puede ofrecer enviarlos por correo electrónico a las partes interesadas (aunque esto reducirá la cantidad de personas que se molestarán en trabajar en eso).
- En realidad, no he visto esto hecho, porque las personas que no pueden divulgar sus datos son sensibles a la hora de publicarlos de cualquier forma, pero parecería plausible que en algunos casos uno podría publicar datos si estuvieran lo suficientemente anonimizados / codificados / corrompidos levemente. de alguna manera.
Si no puede hacer ninguno de estos, probablemente necesite contratar a un consultor para resolver su problema ...
editar : Dos preguntas SO útiles para anonimizar / codificar:
- ¿Cómo crear un conjunto de datos de ejemplo a partir de datos privados (reemplazando los nombres y niveles de las variables con marcadores de posición no informativos)?
- Dado un conjunto de números aleatorios extraídos de una distribución univariante continua, encuentre la distribución
Las respuestas hasta ahora son obviamente excelentes para la parte de reproducibilidad. Esto es simplemente para aclarar que un ejemplo reproducible no puede ni debe ser el único componente de una pregunta. No olvide explicar cómo quiere que se vea y los contornos de su problema, no solo cómo ha intentado llegar hasta ahora. El código no es suficiente; también necesitas palabras.
Aquí hay un ejemplo reproducible de lo que se debe evitar hacer (extraído de un ejemplo real, los nombres cambiados para proteger a los inocentes):
Los siguientes son datos de muestra y parte de la función con la que tengo problemas.
code
code
code
code
code (40 or so lines of it)
Cómo puedo conseguir esto ?
Tengo una forma muy fácil y eficiente de hacer un ejemplo de R que no se ha mencionado anteriormente. Puede definir su estructura en primer lugar. Por ejemplo,
mydata <- data.frame(a=character(0), b=numeric(0), c=numeric(0), d=numeric(0))
>fix(mydata)
Luego, puede ingresar sus datos manualmente. Esto es eficaz para ejemplos más pequeños que para grandes.
Para crear rápidamente una parte dput
de sus datos, simplemente puede copiar (una parte de) los datos en su portapapeles y ejecutar lo siguiente en R:
para datos en Excel:
dput(read.table("clipboard",sep="\t",header=TRUE))
para datos en un archivo txt:
dput(read.table("clipboard",sep="",header=TRUE))
Puede cambiar el sep
en este último si es necesario. Esto solo funcionará si sus datos están en el portapapeles, por supuesto.
Pautas:
Su principal objetivo al elaborar sus preguntas debe ser facilitar que los lectores comprendan y reproduzcan su problema en sus sistemas. Para hacerlo:
- Proporcionar datos de entrada
- Proporcionar el resultado esperado
- Explica tu problema de manera sucinta
- si tiene más de 20 líneas de texto + código, probablemente pueda volver atrás y simplificar
- simplifique su código tanto como sea posible mientras preserva el problema / error
Esto requiere algo de trabajo, pero parece una compensación justa, ya que está pidiendo a otros que trabajen por usted.
Proporcionar datos:
Conjuntos de datos integrados
La mejor opción, con mucho, es confiar en conjuntos de datos integrados. Esto hace que sea muy fácil para otros trabajar en su problema. Escriba data()
en el indicador R para ver qué datos están disponibles para usted. Algunos ejemplos clásicos:
iris
mtcars
ggplot2::diamonds
(paquete externo, pero casi todo el mundo lo tiene)
Inspeccione los conjuntos de datos integrados para encontrar uno adecuado para su problema.
Si puede reformular su problema para utilizar los conjuntos de datos integrados, es mucho más probable que obtenga buenas respuestas (y votos a favor).
Datos autogenerados
Si su problema es muy específico de un tipo de datos que no está representado en los conjuntos de datos existentes, proporcione el código R que genera el conjunto de datos más pequeño posible en el que se manifiesta su problema. Por ejemplo
set.seed(1) # important to make random data reproducible
myData <- data.frame(a=sample(letters[1:5], 20, rep=T), b=runif(20))
Ahora, alguien que intente responder mi pregunta puede copiar / pegar esas dos líneas y comenzar a trabajar en el problema de inmediato.
dput
Como último recurso , puede utilizar dput
para transformar un objeto de datos en código R (por ejemplo dput(myData)
). Digo como "último recurso" porque la salida de a dput
menudo es bastante difícil de manejar, molesta de copiar y pegar y oscurece el resto de su pregunta.
Proporcione el resultado esperado:
Alguien dijo una vez:
Una imagen del resultado esperado vale 1000 palabras
- una persona muy sabia
Si puede agregar algo como "Esperaba obtener este resultado":
cyl mean.hp
1: 6 122.28571
2: 4 82.63636
3: 8 209.21429
a su pregunta, es mucho más probable que las personas comprendan rápidamente lo que está tratando de hacer. Si el resultado esperado es grande y difícil de manejar, probablemente no haya pensado lo suficiente en cómo simplificar su problema (ver a continuación).
Explique su problema de manera sucinta
Lo principal que debe hacer es simplificar su problema tanto como sea posible antes de hacer su pregunta. Reencuadrar el problema para trabajar con los conjuntos de datos integrados ayudará mucho en este sentido. También encontrará a menudo que con solo pasar por el proceso de simplificación, resolverá su propio problema.
A continuación, se muestran algunos ejemplos de buenas preguntas:
- con conjunto de datos incorporado
- con datos generados por el usuario
En ambos casos, es casi seguro que los problemas del usuario no sean con los ejemplos simples que brindan. Más bien, abstrajeron la naturaleza de su problema y lo aplicaron a un conjunto de datos simple para hacer su pregunta.
¿Por qué otra respuesta a esta pregunta?
Esta respuesta se centra en lo que creo que es la mejor práctica: use conjuntos de datos integrados y proporcione lo que espera como resultado en una forma mínima. Las respuestas más destacadas se centran en otros aspectos. No espero que esta respuesta se destaque; esto está aquí únicamente para que pueda vincularlo en los comentarios a las preguntas de los novatos.
El código reproducible es clave para obtener ayuda. Sin embargo, hay muchos usuarios que podrían mostrarse escépticos a la hora de pegar incluso una parte de sus datos. Por ejemplo, podrían estar trabajando con datos confidenciales o en datos originales recopilados para usar en un trabajo de investigación. Por alguna razón, pensé que sería bueno tener una función útil para "deformar" mis datos antes de pegarlos públicamente. La anonymize
función del paquete SciencesPo
es muy tonta, pero para mí funciona bien con la dput
función.
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
Luego lo anonimizo:
> 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
También es posible que desee muestrear algunas variables en lugar de todos los datos antes de aplicar la anonimización y el 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
A menudo, necesita algunos datos para un ejemplo, sin embargo, no desea publicar sus datos exactos. Para usar algún data.frame existente en la biblioteca establecida, use el comando de datos para importarlo.
p.ej,
data(mtcars)
y luego haz el problema
names(mtcars)
your problem demostrated on the mtcars data set
Si tiene un conjunto de datos grande que no se puede poner fácilmente en el script usando dput()
, publique sus datos en pastebin y cárguelos usando read.table
:
d <- read.table("http://pastebin.com/raw.php?i=m1ZJuKLH")
Inspirado por @Henrik .
Estoy desarrollando el paquete de wakefield para abordar esta necesidad de compartir rápidamente datos reproducibles, a veces dput
funciona bien para conjuntos de datos más pequeños, pero muchos de los problemas con los que nos enfrentamos son mucho más grandes, compartir un conjunto de datos tan grande a través de no dput
es práctico.
Sobre:
wakefield permite al usuario compartir código mínimo para reproducir datos. El usuario establecen
(número de filas) y especifica cualquier número de funciones variables preestablecidas (actualmente hay 70) que imitan datos reales (cosas como género, edad, ingresos, etc.)
Instalación:
Actualmente (2015-06-11), wakefield es un paquete de GitHub, pero eventualmente irá a CRAN después de que se escriban las pruebas unitarias. Para instalar rápidamente, use:
if (!require("pacman")) install.packages("pacman")
pacman::p_load_gh("trinker/wakefield")
Ejemplo:
Aquí hay un ejemplo:
r_data_frame(
n = 500,
id,
race,
age,
sex,
hour,
iq,
height,
died
)
Esto 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
.. ... ... ... ... ... ... ... ...
Si tiene una o más factor
variables en sus datos con las que desea que sean reproducibles dput(head(mydata))
, considere agregarlas droplevels
, de modo que los niveles de factores que no están presentes en el conjunto de datos minimizados no se incluyan en su dput
salida, para hacer que el ejemplo sea mínimo :
dput(droplevels(head(mydata)))
Me pregunto si un http://old.r-fiddle.org/El enlace podría ser una forma muy ordenada de compartir un problema. Recibe una identificación única como e incluso se podría pensar en incrustarla en SO.
No pegue las salidas de su consola de esta manera:
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")
)
No podemos copiarlo y pegarlo directamente.
Para que las preguntas y respuestas sean reproducibles correctamente, intente eliminar +
& >
antes de publicarlo y coloque #
resultados y comentarios como este:
#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")
Una cosa más, si ha usado alguna función de cierto paquete, mencione esa biblioteca.
Puedes hacer esto usando reprex .
Como señaló mt1022 , "... un buen paquete para producir un ejemplo mínimo y reproducible es " reprex " de tidyverse ".
Según Tidyverse :
El objetivo de "reprex" es empaquetar su código problemático de tal manera que otras personas puedan ejecutarlo y sentir su dolor.
Se ofrece un ejemplo en el sitio web de tidyverse .
library(reprex)
y <- 1:4
mean(y)
reprex()
Creo que esta es la forma más sencilla de crear un ejemplo reproducible.
Aparte de todas las respuestas anteriores que me parecieron muy interesantes, a veces podría ser muy fácil como se comenta aquí: - CÓMO HACER UN EJEMPLO DE REPRODUCIBLE MÍNIMO PARA OBTENER AYUDA CON R
Hay muchas formas de hacer un vector aleatorio Cree un vector numérico de 100 con valores aleatorios en R redondeados a 2 decimales o una matriz aleatoria en R
mydf1<- matrix(rnorm(20),nrow=20,ncol=5)
Tenga en cuenta que a veces es muy difícil compartir un dato dado debido a varias razones, como la dimensión, etc. Sin embargo, todas las respuestas anteriores son excelentes y muy importantes para pensar y usar cuando se quiere hacer un ejemplo de datos reproducible. Pero tenga en cuenta que para hacer un dato tan representativo como el original (en caso de que el OP no pueda compartir los datos originales), es bueno agregar alguna información con el ejemplo de datos como (si llamamos al dato mydf1)
class(mydf1)
# this shows the type of the data you have
dim(mydf1)
# this shows the dimension of your data
Además, se debe conocer el tipo, la longitud y los atributos de un dato que pueden ser estructuras de datos.
#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))
Estas son algunas de mis sugerencias:
- Intente usar conjuntos de datos R predeterminados
- Si tiene su propio conjunto de datos, inclúyalos con
dput
, para que otros puedan ayudarlo más fácilmente - No lo use a
install.package()
menos que sea realmente necesario, la gente lo entenderá si solo usarequire
olibrary
Trate de ser conciso
- Tener un conjunto de datos
- Intente describir la salida que necesita de la manera más simple posible
- Hágalo usted mismo antes de hacer la pregunta
- Es fácil cargar una imagen, así que cargue parcelas si tiene
- También incluya cualquier error que pueda tener
Todos estos son parte de un ejemplo reproducible.
Es una buena idea usar funciones del testthat
paquete para mostrar lo que espera que ocurra. Por lo tanto, otras personas pueden modificar su código hasta que se ejecute sin errores. Esto alivia la carga de quienes quisieran ayudarlo, porque significa que no tienen que decodificar su descripción textual. Por ejemplo
library(testthat)
# code defining x and y
if (y >= 10) {
expect_equal(x, 1.23)
} else {
expect_equal(x, 3.21)
}
es más claro que "Creo que x resultaría ser 1,23 para y igual o superior a 10, y 3,21 en caso contrario, pero no obtuve ningún resultado". Incluso en este ejemplo tonto, creo que el código es más claro que las palabras. El uso le testthat
permite a su ayudante concentrarse en el código, lo que le ahorra tiempo y le brinda una forma de saber que ha resuelto su problema antes de publicarlo.