2468 votes

Comment faire un très bon exemple reproductible de R ?

Lors de la discussion de la performance avec des collègues, de l'enseignement, de l'envoi d'un rapport de bogue ou à la recherche de conseils sur les listes de diffusion et ici, un exemple reproductible est souvent posée et toujours utile.

Quels sont vos conseils pour la création d'un excellent exemple? Comment coller des structures de données de dans un format de texte? Quelles sont les autres informations devriez-vous inclure?

Existe-il d'autres trucs en plus à l'aide d' dput(), dump() ou structure()? Quand devriez-vous inclure library() ou require() des déclarations? Laquelle des mots réservés, doit-on éviter, en plus de c, df, data, etc?

Comment faire un grand reproductible exemple?

1930voto

Joris Meys Points 38980

Un minimum reproductible exemple se compose des éléments suivants :

  • un minimum de jeu de données, nécessaire pour reproduire l'erreur
  • le minimum praticable code nécessaire pour reproduire l'erreur, qui peut être exécuté sur le jeu de données.
  • les informations nécessaires sur les emballages, R version et le système d'exécution.
  • dans le cas de processus aléatoires, une graine (défini par set.seed()) pour la reproductibilité

En regardant les exemples dans les fichiers d'aide des fonctions est souvent utile. En général, tout le code donné, il répond aux exigences d'un minimum reproductible exemple : les données sont fournies, un minimum de code est fourni, et tout est praticable.

La production d'un minimum de dataset

Pour la plupart des cas, cela peut être fait facilement en fournissant seulement un vecteur / dataframe avec certaines valeurs. Ou vous pouvez utiliser l'un des ensembles de données, qui sont fournis avec la plupart des paquets.

Faire un vecteur est facile. Il est parfois nécessaire d'ajouter un peu de hasard, et il y a un certain nombre de fonctions pour faire que. sample() peut randomize un vecteur, ou de donner un vecteur aléatoire avec seulement quelques valeurs. letters est un vecteur utile contenant de l'alphabet. Cela peut être utilisé pour faire des facteurs.

Quelques exemples :

  • valeurs aléatoires : x <- rnorm(10) pour une distribution normale, x <- runif(10) pour une distribution uniforme, ...
  • une permutation de certaines valeurs : x <- sample(1:10) pour les vecteurs 1:10 dans un ordre aléatoire.
  • un facteur aléatoire : x <- sample(letters[1:4], 20, replace = TRUE)

Pour les matrices, on peut utiliser matrix(), par exemple :

matrix(1:10, ncol = 2)

Faire dataframes peut être fait en utilisant data.frame(). On doit prêter attention à nom les entrées dans le dataframe, et pour ne pas faire trop compliqué.

Un exemple :

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

Pour certaines questions, des formats spécifiques peuvent être nécessaires. Pour ces derniers, on peut utiliser de l' as.someType fonctions : as.factor, as.Date, as.xts, "Ces, en combinaison avec le vecteur et/ou un dataframe astuces.

La copie de vos données

Si vous avez quelques données que ce serait trop difficile à construire à l'aide de ces conseils, alors vous pouvez toujours faire un sous-ensemble de vos données d'origine, en utilisant par exemple head(), subset() ou les indices. Ensuite, utilisez par exemple. dput() pour nous donner quelque chose qui peut être mis dans la R immédiatement :

> 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")

Le pire scénario, vous pouvez donner une représentation de texte qui peut être lu à l'aide de l' text paramètre 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)

En produisant un minimum de code

Cela devrait être la partie la plus facile, mais n'est pas souvent. Ce que vous ne devriez pas faire est :

  • ajouter tous les types de conversions de données. Assurez-vous que les données fournies est déjà dans le format correct (à moins que ce soit le problème, bien sûr)
  • copier-coller l'ensemble de la fonction / morceau de code qui donne une erreur. Essayez d'abord de localiser les lignes de résultat dans l'erreur. Plus souvent que pas, vous saurez quel est le problème vous-même.

Ce que vous devez faire est :

  • ajouter les paquets doivent être utilisés si vous en utilisez un.
  • si vous ouvrez les connexions ou de rendre des fichiers, ajouter un peu de code pour les fermer ou de supprimer les fichiers (à l'aide d' unlink())
  • si vous modifiez des options, assurez-vous que le code contient une déclaration de revenir en arrière à l'original. (par exemple, op <- par(mfrow=c(1,2)) ...some code... par(op) )
  • testrun votre code dans un nouveau, vide de R session assurez-vous que le code exécutable. Les gens devraient être en mesure de simplement copier-coller de vos données et de votre code dans la console et obtenir exactement le même que vous avez.

Donner des informations supplémentaires

Dans la plupart des cas, la version R et le système d'exploitation suffira. Lorsque des conflits surviennent avec des packages, donnant à la sortie de l' sessionInfo() peut vraiment aider. Lorsque l'on parle de connexions à d'autres applications (que ce soit via ODBC ou quoi que ce soit d'autre), il convient également de fournir les numéros de version pour ceux-ci, et si possible aussi les informations nécessaires sur le programme d'installation.

642voto

hadley Points 33766

(Voici mon conseil de http://adv-r.had.co.nz/Reproducibility.html. J'ai essayé de faire court mais doux)

Comment écrire un exemple reproductible.

Vous êtes plus susceptibles d'obtenir de bons d'aide avec votre R problème si vous fournissez un exemple reproductible. Un exemple reproductible permet à quelqu'un d'autre pour recréer votre problème simplement en copiant et en collant R code.

Il y a quatre choses que vous devez inclure pour faire de votre exemple reproductible: les paquets requis, les données, le code, et une description de vos R l'environnement.

  • Les paquets doivent être chargés dans le haut du script, il est donc facile de voir ceux qui l'exemple des besoins.

  • La façon la plus simple d'inclure les données dans un e-mail ou de Débordement de Pile question est d'utiliser dput() pour générer la R du code de la recréer. Par exemple, pour recréer l' mtcars jeu de données dans R, J'avais effectuez les étapes suivantes:

    1. Exécutez dput(mtcars) dans la R
    2. Copier la sortie
    3. Dans mon reproductible script, tapez mtcars <- puis coller.
  • Passez un peu de temps à ce que votre code est facile pour les autres de lire:

    • assurez-vous d'avoir utilisé des espaces et vos noms de variable sont concis, mais instructif

    • utilisez les commentaires pour indiquer où se trouve votre problème réside

    • faites de votre mieux pour enlever tout ce qui n'est pas lié au problème.
      La plus courte de votre code, plus il est facile à comprendre.

  • Inclure la sortie de l' sessionInfo() dans un commentaire dans le code. Ce qui résume votre R de l'environnement et permet de vérifier facilement si vous utilisez un out-of-date package.

Vous pouvez vérifier que vous avez effectué un exemple reproductible par le démarrage d'une nouvelle session R et coller votre script.

Avant de mettre votre code dans un e-mail, envisager de mettre sur http://gist.github.com/. Il donnera à votre code de nice, de la syntaxe, et vous n'avez pas à vous soucier de rien obtenir pervertis par le système de messagerie.

338voto

Roman Luštrik Points 19295

Personnellement, je préfère la "une" des doublures. Quelque chose le long des lignes de:

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 structure de données doit imiter l'idée de l'écrivain du problème, et ce n'est pas exactement mot à mot de la structure. J'ai vraiment l'apprécier lorsque les variables ne sont pas écraser mes propres variables ou à dieu ne plaise, les fonctions (comme df).

Alternativement, on peut couper un peu les coins et le point à un pré-ensembles de données existants, quelque chose comme:

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

N'oubliez pas de mentionner des paquets spéciaux que vous pourriez être en utilisant.

Si vous essayez de démontrer quelque chose sur des objets plus volumineux, vous pouvez essayer

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

Si vous travaillez avec des données spatiales via l' raster package, vous pouvez générer des données aléatoires. Beaucoup d'exemples peuvent être trouvés dans le paquet de la vignette, mais voici une petite pépite.

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 vous êtes dans le besoin de certains spatiale de l'objet, tel qu'appliqué en sp, vous pouvez obtenir des ensembles de données via des fichiers externes (comme le fichier de forme ESRI) dans "spatiale" packages (voir la vue Spatiale dans la Tâche de Vues).

library(rgdal)
ogrDrivers()
dsn <- system.file("vectors", package = "rgdal")[1]
ogrListLayers(dsn)
ogrInfo(dsn=dsn, layer="cities")
cities <- readOGR(dsn=dsn, layer="cities")

315voto

Ricardo Saporta Points 22951

Inspiré par ce post, je vais maintenant utiliser une fonction très pratique
reproduce(<mydata>) quand j'ai besoin de poster sur StackOverflow.

INSTRUCTIONS RAPIDES

Si myData est le nom de votre objet à reproduire, exécuter les opérations suivantes dans R:

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

reproduce(myData)

Détails:

Cette fonction est un intelligent gestionnaire d' dput et effectue les opérations suivantes:

  • automatiquement des échantillons d'un grand ensemble de données (basé sur la taille et la classe. La taille de l'échantillon peut être ajustée)
  • crée un dput sortie
  • vous permet de spécifier laquelle des colonnes à l'exportation
  • ajoute à l'avant de celui - objName <- ... , de sorte qu'il peut être facilement copier+coller, mais...
  • Si vous travaillez sur un mac, la sortie est automatiquement copié dans le presse-papiers, de sorte que vous pouvez simplement l'exécuter, puis coller à votre question.

La source est disponible ici:


Exemple:

# 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 est d'environ 100 x 102. Je veux échantillon de 10 lignes, et quelques colonnes spécifiques

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

Donne le résultat suivant:

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==

Notez également que l'intégralité de la production est dans une belle ligne unique, longue, pas un grand paragraphe de couper les lignes. Cela rend plus facile à lire sur tant de questions posts et aussi plus facile à copier+coller.

______________________________________

Mise À Jour Octobre 2013:

Vous pouvez maintenant spécifier le nombre de lignes de texte de sortie va en prendre (c'est à dire, ce que vous allez coller dans StackOverflow). Utiliser l' lines.out=n argument en faveur de cette. Exemple:

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

    ==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==

222voto

Sacha Epskamp Points 14956

Voici un bon guide:

http://www.r-bloggers.com/three-tips-for-posting-good-questions-to-r-help-and-stack-overflow/

Mais le plus important: assurez-vous que vous faites un petit morceau de code que nous pouvons exécuter pour voir quel est le problème. Une fonction utile pour ce est - dput(), mais si vous avez des données très volumineux, vous voudrez peut-être faire un petit échantillon de données ou seulement les 10 premières lignes.

EDIT:

Assurez-vous également que vous avez identifié où est le problème vous-même. L'exemple ne doit pas être un ensemble de script R avec "Sur la ligne de 200 il y a une erreur". Si vous utilisez les outils de débogage dans R (I love browser()) et google, vous devriez être en mesure de vraiment identifier où est le problème et reproduire un exemple trivial où la même chose se passe mal.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X