Comment créer un excellent exemple R reproductible

May 11 2011

Lors de discussions sur les performances avec des collègues, l'enseignement, l'envoi d'un rapport de bogue ou la recherche de conseils sur les listes de diffusion et ici sur Stack Overflow, un exemple reproductible est souvent demandé et toujours utile.

Quels sont vos conseils pour créer un excellent exemple? Comment coller les structures de données de r dans un format texte? Quelles autres informations devez-vous inclure?

Existe-t-il d'autres astuces en plus de l'utilisation dput(), dump()ou structure()? Quand devez-vous inclure des déclarations library()ou require()? Ce qui a des mots réservés doit - on éviter, en plus c, df, data, etc.?

Comment peut - on faire un grand r exemple reproductible?

Réponses

1756 JorisMeys May 11 2011 at 18:40

Un exemple minimal reproductible comprend les éléments suivants:

  • un ensemble de données minimal, nécessaire pour démontrer le problème
  • le code exécutable minimal nécessaire pour reproduire l'erreur, qui peut être exécuté sur l'ensemble de données donné
  • les informations nécessaires sur les packages utilisés, la version R et le système sur lequel il est exécuté.
  • dans le cas de processus aléatoires, une graine (définie par set.seed()) pour la reproductibilité 1

Pour obtenir des exemples de bons exemples reproductibles minimaux , consultez les fichiers d'aide de la fonction que vous utilisez. En général, tout le code qui y est donné répond aux exigences d'un exemple reproductible minimal: des données sont fournies, un code minimal est fourni et tout est exécutable. Regardez également les questions sur Stack Overflow avec beaucoup de votes positifs.

Produire un ensemble de données minimal

Dans la plupart des cas, cela peut être facilement fait en fournissant simplement un cadre vectoriel / de données avec certaines valeurs. Ou vous pouvez utiliser l'un des ensembles de données intégrés, qui sont fournis avec la plupart des packages.
Une liste complète des ensembles de données intégrés peut être consultée avec library(help = "datasets"). Il y a une brève description de chaque ensemble de données et plus d'informations peuvent être obtenues, par exemple avec ?mtcarsoù «mtcars» est l'un des ensembles de données de la liste. D'autres packages peuvent contenir des ensembles de données supplémentaires.

Créer un vecteur est facile. Parfois, il est nécessaire d'y ajouter un peu de caractère aléatoire, et il existe un certain nombre de fonctions pour le faire. sample()peut randomiser un vecteur, ou donner un vecteur aléatoire avec seulement quelques valeurs. lettersest un vecteur utile contenant l'alphabet. Cela peut être utilisé pour créer 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 le vecteur 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)

La création de trames de données peut être effectuée en utilisant data.frame(). Il faut faire attention à nommer les entrées dans la trame de données et à ne pas la compliquer trop.

Un exemple :

set.seed(1)
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 ceux - ci, on peut utiliser les fournis as.someTypefonctions: as.factor, as.Date, as.xts, ... Ces en combinaison avec le vecteur et / ou astuces trame de données.

Copiez vos données

Si vous avez des données qui seraient trop difficiles à construire en utilisant ces conseils, vous pouvez toujours faire un sous - ensemble de vos données d' origine, en utilisant head(), subset()ou les indices. Ensuite, utilisez dput()pour nous donner quelque chose qui peut être mis dans R immédiatement:

> 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 votre bloc de données a un facteur avec plusieurs niveaux, la dputsortie peut être compliquée car elle répertorie toujours tous les niveaux de facteur possibles même s'ils ne sont pas présents dans le sous-ensemble de vos données. Pour résoudre ce problème, vous pouvez utiliser la droplevels()fonction. Remarquez ci-dessous comment l'espèce est un facteur à un seul niveau:

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

Lors de l'utilisation dput, vous pouvez également inclure uniquement les colonnes pertinentes:

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

Une autre mise en garde dputest que cela ne fonctionnera pas pour les data.tableobjets à clé ou pour les groupes tbl_df(classe grouped_df) à partir de dplyr. Dans ces cas , vous pouvez reconvertir en une trame de données régulière avant le partage, dput(as.data.frame(my_data)).

Dans le pire des cas, vous pouvez donner une représentation textuelle qui peut être lue en utilisant le textparamè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)

Produire un code minimal

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

  • ajoutez toutes sortes de conversions de données. Assurez-vous que les données fournies sont déjà dans le bon format (à moins que ce ne soit le problème bien sûr)
  • copier-coller une fonction entière / un morceau de code qui donne une erreur. Tout d'abord, essayez de localiser les lignes qui génèrent exactement l'erreur. Le plus souvent, vous découvrirez vous-même quel est le problème.

Ce que vous devez faire, c'est:

  • ajoutez les packages à utiliser si vous en utilisez (en utilisant library())
  • si vous ouvrez des connexions ou créez des fichiers, ajoutez du code pour les fermer ou supprimez les fichiers (en utilisant unlink())
  • si vous modifiez des options, assurez-vous que le code contient une instruction pour les restaurer à l'origine. (par exemple op <- par(mfrow=c(1,2)) ...some code... par(op))
  • test exécutez votre code dans une nouvelle session R vide pour vous assurer que le code est exécutable. Les gens devraient pouvoir simplement copier-coller vos données et votre code dans la console et obtenir exactement la même chose que vous.

Donner des informations supplémentaires

Dans la plupart des cas, seuls la version R et le système d'exploitation suffiront. Lorsque des conflits surviennent avec des packages, donner la sortie de sessionInfo()peut vraiment aider. Lorsque vous parlez de connexions à d'autres applications (que ce soit via ODBC ou autre), il convient également de fournir les numéros de version de celles-ci, et si possible également les informations nécessaires sur l'installation.

Si vous utilisez R dans R studio en utilisant rstudioapi::versionInfo()peut être utile de signaler votre version rstudio.

Si vous rencontrez un problème avec un package spécifique, vous souhaiterez peut-être fournir la version du package en donnant la sortie de packageVersion("name of the package").


1 Remarque: la sortie de set.seed()diffère entre R> 3.6.0 et les versions précédentes. Spécifiez la version R que vous avez utilisée pour le processus aléatoire et ne soyez pas surpris si vous obtenez des résultats légèrement différents lorsque vous suivez d'anciennes questions. Pour obtenir le même résultat dans de tels cas, vous pouvez utiliser la fonction RNGversion()-avant set.seed()(par exemple :) RNGversion("3.5.2").

595 hadley May 11 2011 at 20:57

(Voici mon conseil dans Comment écrire un exemple reproductible . J'ai essayé de le rendre court mais agréable)

Comment écrire un exemple reproductible.

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

Vous devez inclure quatre éléments pour rendre votre exemple reproductible: les packages requis, les données, le code et une description de votre environnement R.

  • Les packages doivent être chargés en haut du script, il est donc facile de voir ceux dont l'exemple a besoin.

  • Le moyen le plus simple d'inclure des données dans un e-mail ou une question de débordement de pile consiste dput()à générer le code R pour le recréer. Par exemple, pour recréer l' mtcarsensemble de données dans R, j'effectuerais les étapes suivantes:

    1. Courir dput(mtcars)en R
    2. Copiez la sortie
    3. Dans mon script reproductible, tapez mtcars <-puis collez.
  • Passez un peu de temps à vous assurer que votre code est facile à lire pour les autres:

    • assurez-vous que vous avez utilisé des espaces et que les noms de vos variables sont concis, mais informatifs

    • utilisez des commentaires pour indiquer où se situe votre problème

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

  • Incluez la sortie de sessionInfo()dans un commentaire dans votre code. Cela résume votre environnement R et permet de vérifier facilement si vous utilisez un package obsolète.

Vous pouvez vérifier que vous avez réellement créé un exemple reproductible en démarrant une nouvelle session R et en collant votre script.

Avant de mettre tout votre code dans un email, pensez à le mettre sur Gist github . Cela donnera à votre code une belle coloration syntaxique, et vous n'aurez pas à vous soucier de quoi que ce soit qui soit mutilé par le système de messagerie.

307 RomanLuštrik May 11 2011 at 18:22

Personnellement, je préfère les doublures "one". Quelque chose dans le sens:

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 du problème de l'écrivain et non la structure textuelle exacte. J'apprécie vraiment que les variables n'écrasent pas mes propres variables ou que Dieu m'en garde, des fonctions (comme df).

Alternativement, on pourrait couper quelques coins et pointer vers un ensemble de données préexistant, quelque chose comme:

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

N'oubliez pas de mentionner les packages spéciaux que vous pourriez utiliser.

Si vous essayez de démontrer quelque chose sur des objets plus grands, 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 le rasterpackage, vous pouvez générer des données aléatoires. De nombreux exemples peuvent être trouvés dans la vignette du package, 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 avez besoin d'un objet spatial tel qu'implémenté dans sp, vous pouvez obtenir des ensembles de données via des fichiers externes (comme le fichier de formes ESRI) dans des packages "spatiaux" (voir la vue spatiale dans les vues des tâches).

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

Inspiré par cet article, j'utilise maintenant une fonction pratique
reproduce(<mydata>)lorsque j'ai besoin de publier sur StackOverflow.


INSTRUCTIONS RAPIDES

Si myDataest le nom de votre objet à reproduire, exécutez la commande suivante dans R:

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

reproduce(myData)

Des détails:

Cette fonction est un wrapper intelligent dputet effectue les opérations suivantes:

  • échantillonne automatiquement un grand ensemble de données (en fonction de la taille et de la classe. La taille de l'échantillon peut être ajustée)
  • crée une dputsortie
  • vous permet de spécifier qui colonnes à exporter
  • ajoute à l'avant de celui-ci objName <- ...afin qu'il puisse être facilement copié + collé, mais ...
  • Si vous travaillez sur un mac, la sortie est automatiquement copiée dans le presse-papiers, de sorte que vous pouvez simplement l'exécuter, puis la coller à votre question.

La source est disponible ici:

  • Github - pubR / reproduce.R

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 souhaite échantillonner 10 lignes et quelques colonnes spécifiques

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

Donne la sortie suivante:

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 sortie est dans une belle et longue ligne unique, pas un grand paragraphe de lignes hachées. Cela facilite la lecture des messages sur les questions SO et facilite également le copier-coller.


Mise à jour d'octobre 2013:

Vous pouvez maintenant spécifier le nombre de lignes de texte que prendra la sortie (c'est-à-dire ce que vous collerez dans StackOverflow). Utilisez l' lines.out=nargument pour cela. Exemple:

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

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

Voici un bon guide .

Le point le plus important est le suivant: assurez-vous simplement de créer un petit morceau de code que nous pouvons exécuter pour voir quel est le problème . Une fonction utile pour cela est dput(), mais si vous avez des données très volumineuses, vous voudrez peut-être créer un petit exemple de jeu de données ou utiliser uniquement les 10 premières lignes environ.

ÉDITER:

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

167 RichieCotton May 11 2011 at 20:17

La liste de diffusion R-help contient un guide de publication qui couvre à la fois les questions posées et les réponses aux questions, y compris un exemple de génération de données:

Exemples: il est parfois utile de fournir un petit exemple que quelqu'un peut réellement exécuter. Par exemple:

Si j'ai une matrice x comme suit:

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

comment puis-je le transformer en un dataframe avec 8 lignes et trois colonnes nommées 'row', 'col' et 'value', qui ont les noms de dimension comme valeurs de 'row' et 'col', comme ceci:

  > x.df
     row col value
  1    A   x      1

...
(à laquelle la réponse pourrait être:

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

)

Le mot petit est particulièrement important. Vous devez viser un exemple reproductible minimal , ce qui signifie que les données et le code doivent être aussi simples que possible pour expliquer le problème.

EDIT: Un joli code est plus facile à lire qu'un code laid. Utilisez un guide de style .

164 Paolo Jun 29 2012 at 15:32

Depuis R.2.14 (je suppose), vous pouvez alimenter votre représentation textuelle de données directement à 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

Parfois, le problème n'est pas vraiment reproductible avec un petit morceau de données, peu importe vos efforts, et ne se produit pas avec des données synthétiques (bien qu'il soit utile de montrer comment vous avez produit des ensembles de données synthétiques qui n'ont pas reproduit le problème, car il exclut certaines hypothèses).

  • Il peut être nécessaire de publier les données sur le Web quelque part et de fournir une URL.
  • Si les données ne peuvent pas être communiquées au grand public mais qu'elles pourraient être partagées du tout, vous pourrez peut-être proposer de les envoyer par courrier électronique aux parties intéressées (bien que cela réduise le nombre de personnes qui prendront la peine de travailler. dessus).
  • Je n'ai pas vraiment vu cela fait, parce que les personnes qui ne peuvent pas divulguer leurs données sont sensibles à l'idée de les publier sous quelque forme que ce soit, mais il semblerait plausible que dans certains cas, on puisse toujours publier des données si elles étaient suffisamment anonymisées / brouillées / légèrement corrompues. en quelque sorte.

Si vous ne pouvez pas faire l'un ou l'autre de ces éléments, vous devrez probablement engager un consultant pour résoudre votre problème ...

edit : Deux questions SO utiles pour l'anonymisation / le brouillage:

  • Comment créer un exemple d'ensemble de données à partir de données privées (en remplaçant les noms de variables et les niveaux par des espaces réservés non informatifs)?
  • Étant donné un ensemble de nombres aléatoires tirés d'une distribution continue univariée, trouvez la distribution
136 AriB.Friedman Jul 09 2012 at 22:41

Les réponses à ce jour sont évidemment excellentes pour la partie reproductibilité. Il s'agit simplement de clarifier qu'un exemple reproductible ne peut et ne doit pas être la seule composante d'une question. N'oubliez pas d'expliquer à quoi vous voulez qu'il ressemble et les contours de votre problème, pas seulement comment vous avez tenté d'y arriver jusqu'à présent. Le code ne suffit pas; vous avez également besoin de mots.

Voici un exemple reproductible de ce qu'il faut éviter de faire (tiré d'un exemple réel, les noms ont été modifiés pour protéger les innocents):


Voici des exemples de données et une partie de la fonction avec laquelle j'ai des problèmes.

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

Comment puis-je atteindre cet objectif ?


124 jasmine_007 Feb 20 2014 at 16:11

J'ai un moyen très simple et efficace de créer un exemple R qui n'a pas été mentionné ci-dessus. Vous pouvez d'abord définir votre structure. Par exemple,

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

>fix(mydata)

Ensuite, vous pouvez saisir vos données manuellement. Ceci est efficace pour les petits exemples plutôt que pour les grands.

119 JT85 Apr 10 2013 at 21:51

Pour créer rapidement une dputde vos données, vous pouvez simplement copier (une partie de) les données dans votre presse-papiers et exécuter ce qui suit dans R:

pour les données dans Excel:

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

pour les données dans un fichier txt:

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

Vous pouvez changer le sepdans ce dernier si nécessaire. Cela ne fonctionnera que si vos données sont bien sûr dans le presse-papiers.

118 BrodieG Feb 12 2015 at 22:24

Des lignes directrices:


Votre objectif principal dans l'élaboration de vos questions devrait être de permettre aux lecteurs de comprendre et de reproduire votre problème aussi facilement que possible sur leurs systèmes. Faire cela:

  1. Fournir des données d'entrée
  2. Fournir le résultat attendu
  3. Expliquez succinctement votre problème
    • si vous avez plus de 20 lignes de texte + code, vous pouvez probablement revenir en arrière et simplifier
    • simplifiez au maximum votre code tout en préservant le problème / l'erreur

Cela demande du travail mais semble être un compromis équitable puisque vous demandez à d'autres de faire du travail pour vous.

Fournir des données:


Ensembles de données intégrés

La meilleure option est de loin de s'appuyer sur des ensembles de données intégrés. Cela permet aux autres de travailler très facilement sur votre problème. Tapez data()à l'invite R pour voir quelles données vous sont disponibles. Quelques exemples classiques:

  • iris
  • mtcars
  • ggplot2::diamonds (paquet externe, mais presque tout le monde l'a)

Inspectez les ensembles de données intégrés pour en trouver un adapté à votre problème.

Si vous êtes en mesure de reformuler votre problème pour utiliser les ensembles de données intégrés, vous êtes beaucoup plus susceptible d'obtenir de bonnes réponses (et des votes positifs).

Données auto-générées

Si votre problème est très spécifique à un type de données qui n'est pas représenté dans les ensembles de données existants, fournissez le code R qui génère le plus petit ensemble de données possible sur lequel votre problème se manifeste. Par exemple

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

Maintenant, quelqu'un essayant de répondre à ma question peut copier / coller ces deux lignes et commencer immédiatement à travailler sur le problème.

dput

En dernier recours , vous pouvez utiliser dputpour transformer un objet de données en code R (par exemple dput(myData)). Je dis en "dernier recours" car la sortie de dputest souvent assez lourde, ennuyeuse à copier-coller, et obscurcit le reste de votre question.

Fournir les résultats attendus:


Quelqu'un a dit un jour:

Une image de la sortie attendue vaut 1000 mots

- une personne très sage

Si vous pouvez ajouter quelque chose comme "Je m'attendais à obtenir ce résultat":

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

à votre question, les gens sont beaucoup plus susceptibles de comprendre rapidement ce que vous essayez de faire. Si le résultat escompté est important et peu maniable, c'est que vous n'avez probablement pas suffisamment réfléchi à la manière de simplifier votre problème (voir ci-dessous).

Expliquez succinctement votre problème


La principale chose à faire est de simplifier au maximum votre problème avant de poser votre question. Recadrer le problème pour qu'il fonctionne avec les ensembles de données intégrés aidera beaucoup à cet égard. Vous constaterez également souvent qu'en passant simplement par le processus de simplification, vous répondrez à votre propre problème.

Voici quelques exemples de bonnes questions:

  • avec jeu de données intégré
  • avec les données générées par l' utilisateur

Dans les deux cas, les problèmes de l'utilisateur ne sont certainement pas liés aux exemples simples qu'ils fournissent. Ils ont plutôt fait abstraction de la nature de leur problème et l'ont appliqué à un simple ensemble de données pour poser leur question.

Pourquoi encore une autre réponse à cette question?


Cette réponse se concentre sur ce que je pense être la meilleure pratique: utilisez des ensembles de données intégrés et fournissez ce que vous attendez en conséquence sous une forme minimale. Les réponses les plus importantes se concentrent sur d'autres aspects. Je ne m'attends pas à ce que cette réponse prenne de l'importance; c'est ici uniquement pour que je puisse y faire un lien dans les commentaires aux questions des débutants.

113 daniel Nov 27 2014 at 09:02

Un code reproductible est essentiel pour obtenir de l'aide. Cependant, de nombreux utilisateurs pourraient être sceptiques quant à l'idée de coller ne serait-ce qu'une partie de leurs données. Par exemple, ils pourraient travailler avec des données sensibles ou sur des données originales collectées pour être utilisées dans un document de recherche. Pour une raison quelconque, j'ai pensé que ce serait bien d'avoir une fonction pratique pour "déformer" mes données avant de les coller publiquement. La anonymizefonction du package SciencesPoest très idiote, mais pour moi, cela fonctionne bien avec la dputfonction.

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

Ensuite, je l'anonymise:

> 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

On peut également vouloir échantillonner quelques variables au lieu de l'ensemble des données avant d'appliquer l'anonymisation et la commande 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

Souvent, vous avez besoin de données pour un exemple, mais vous ne voulez pas publier vos données exactes. Pour utiliser un data.frame existant dans une bibliothèque établie, utilisez la commande data pour l'importer.

par exemple,

data(mtcars)

puis fais le problème

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

Si vous avez un grand ensemble de données qui ne peut pas être facilement mis dans le script en utilisant dput(), publiez vos données dans pastebin et chargez-les en utilisant read.table:

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

Inspiré par @Henrik .

90 TylerRinker Jun 11 2015 at 20:57

Je développe le package wakefield pour répondre à ce besoin de partager rapidement des données reproductibles, dputfonctionne parfois très bien pour des ensembles de données plus petits, mais la plupart des problèmes que nous traitons sont beaucoup plus importants, le partage d'un ensemble de données aussi volumineux via dputn'est pas pratique.

À propos de:

wakefield permet à l'utilisateur de partager un code minimal pour reproduire des données. L'utilisateur définitn(nombre de lignes) et spécifie n'importe quel nombre de fonctions variables prédéfinies (il y en a actuellement 70) qui imitent les données réelles si (des choses comme le sexe, l'âge, le revenu, etc.)

Installation:

Actuellement (11/06/2015), wakefield est un package GitHub mais ira éventuellement au CRAN après l'écriture des tests unitaires. Pour installer rapidement, utilisez:

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

Exemple:

Voici un exemple:

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

Cela produit:

    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

Si vous avez une ou plusieurs factorvariables dans vos données avec lesquelles vous souhaitez rendre reproductibles dput(head(mydata)), envisagez d'y ajouter droplevels, de sorte que les niveaux de facteurs qui ne sont pas présents dans l'ensemble de données minimisé ne soient pas inclus dans votre dputsortie, afin de rendre l'exemple minimal :

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

Je me demande si un http://old.r-fiddle.org/lien pourrait être une manière très intéressante de partager un problème. Il reçoit un identifiant unique comme et on pourrait même penser à l'intégrer dans SO.

49 user2100721 Jul 22 2016 at 17:01

Veuillez ne pas coller les sorties de votre console comme ceci:

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

On ne peut pas le copier-coller directement.

Pour rendre les questions et réponses correctement reproductibles, essayez de supprimer +& >avant de le publier et de mettre #des résultats et des commentaires comme celui-ci:

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

Encore une chose, si vous avez utilisé une fonction d'un certain paquet, mentionnez cette bibliothèque.

34 andrii Aug 19 2017 at 02:02

Vous pouvez le faire en utilisant reprex .

Comme l'a noté mt1022 , "... un bon paquet pour produire un exemple minimal et reproductible est " reprex " de tidyverse ".

Selon Tidyverse :

Le but de "reprex" est de conditionner votre code problématique de manière à ce que d'autres personnes puissent l'exécuter et ressentir votre douleur.

Un exemple est donné sur le site Web de tidyverse .

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

Je pense que c'est le moyen le plus simple de créer un exemple reproductible.

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

En dehors de toutes les réponses ci-dessus que j'ai trouvées très intéressantes, cela pourrait parfois être très facile car il est discuté ici: - COMMENT FAIRE UN EXEMPLE MINIMAL REPRODUCTIBLE POUR OBTENIR DE L'AIDE AVEC R

Il existe de nombreuses façons de créer un vecteur aléatoire Créer un vecteur numérique de 100 avec des valeurs aléatoires dans R arrondies à 2 décimales ou une matrice aléatoire dans R

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

Notez que parfois il est très difficile de partager une donnée donnée pour diverses raisons telles que la dimension etc. Cependant, toutes les réponses ci-dessus sont excellentes et très importantes à penser et à utiliser lorsque l'on veut faire un exemple de données reproductibles. Mais notez que pour rendre une donnée aussi représentative que l'original (au cas où l'OP ne pourrait pas partager les données d'origine), il est bon d'ajouter des informations avec l'exemple de données comme (si nous appelons les données mydf1)

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

De plus, il faut connaître le type, la longueur et les attributs d'une donnée qui peut être des structures de données

#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

Voici quelques-unes de mes suggestions:

  • Essayez d'utiliser les ensembles de données R par défaut
  • Si vous avez votre propre ensemble de données, incluez-les avec dput, afin que d'autres puissent vous aider plus facilement
  • Ne pas utiliser install.package()sauf si c'est vraiment nécessaire, les gens comprendront si vous utilisez simplement requireoulibrary
  • Essayez d'être concis,

    • Avoir un ensemble de données
    • Essayez de décrire le résultat dont vous avez besoin aussi simplement que possible
    • Faites-le vous-même avant de poser la question
  • Il est facile de télécharger une image, alors téléchargez des graphiques si vous avez
  • Incluez également toutes les erreurs que vous pourriez avoir

Tout cela fait partie d'un exemple reproductible.

18 dank Apr 05 2017 at 04:08

C'est une bonne idée d'utiliser les fonctions du testthatpackage pour montrer ce que vous prévoyez de se produire. Ainsi, d'autres personnes peuvent modifier votre code jusqu'à ce qu'il s'exécute sans erreur. Cela allège le fardeau de ceux qui aimeraient vous aider, car cela signifie qu'ils n'ont pas à décoder votre description textuelle. Par exemple

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

est plus clair que "Je pense que x serait égal à 1,23 pour y égal ou supérieur à 10, et 3,21 sinon, mais je n'ai obtenu aucun résultat". Même dans cet exemple idiot, je pense que le code est plus clair que les mots. L'utilisation testthatpermet à votre assistant de se concentrer sur le code, ce qui lui fait gagner du temps et lui permet de savoir qu'il a résolu votre problème, avant de le publier.