web-dev-qa-db-fra.com

Comment faire un bon exemple reproductible R

Lorsque vous discutez de performances avec vos collègues, que vous enseignez, envoyez un rapport de bogue ou recherchez des 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 des structures de données de r dans un format texte? Quelles autres informations devriez-vous inclure?

Existe-t-il d'autres astuces en plus de l'utilisation de dput(), dump() ou structure()? Quand faut-il inclure les instructions library() ou require()? Quels mots réservés faut-il éviter, en plus de c, df, data, etc.?

Comment fait-on un bon exemple r reproductible?

2474
Andrie

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

  • un ensemble de données minimal, nécessaire pour reproduire l'erreur
  • le code minimal exécutable 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é

remarque importante: La sortie de set.seed() diffère entre R> 3.6.0 et les versions précédentes. Spécifiez la version de R que vous avez utilisée pour le processus aléatoire.

Il est souvent utile de consulter les exemples dans les fichiers d’aide des fonctions utilisées. En général, tout le code qui y est donné remplit les conditions requises pour un exemple reproductible minimal: les données sont fournies, le code minimal est fourni et tout est exécutable.

Produire un jeu de données minimal

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

Faire un vecteur est facile. Parfois, il est nécessaire d’ajouter de l’aléatoire à cela, et il existe toute une série de fonctions pour le rendre. sample() peut randomiser un vecteur ou donner un vecteur aléatoire avec seulement quelques valeurs. letters est un vecteur utile contenant l'alphabet. Ceci 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 avec data.frame(). Veillez à nommer les entrées dans le bloc de données et à ne pas le compliquer excessivement.

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 l’une des fonctions as.someType fournies: as.factor, as.Date, as.xts, ... en combinaison avec les astuces de trames de vecteur et/ou de données .

Copiez vos données

Si vous avez des données qu'il serait trop difficile de construire avec ces astuces, vous pouvez toujours créer un sous-ensemble de vos données d'origine, en utilisant par exemple head(), subset() ou les index. Ensuite, utilisez par exemple. dput() pour nous donner quelque chose qui peut être mis immédiatement dans R:

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

Si votre trame de données a un facteur à plusieurs niveaux, la sortie dput peut être difficile à manier car elle répertorie 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 fonction droplevels(). Remarquez ci-dessous comment l’espèce est un facteur avec un seul niveau:

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

Un autre inconvénient pour dput est qu'il ne fonctionnera pas pour les objets data.table clés ou pour les groupés tbl_df (classe grouped_df) à partir de dplyr. Dans ces cas, vous pouvez reconvertir en trame de données normale 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 à l'aide du paramètre text 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:

  • ajouter 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 bien entendu le problème)
  • copier-coller toute une fonction/morceau de code qui donne une erreur. Premièrement, essayez de localiser les lignes qui provoquent exactement l’erreur. Plus souvent qu'autrement, vous découvrirez le problème vous-même.

Ce que vous devriez faire, c'est:

  • ajoutez quels paquets doivent être utilisés 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 les options, assurez-vous que le code contient une instruction pour les rétablir. (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 qu'il 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, seule la version R et le système d'exploitation suffiront. Quand des conflits surviennent avec des paquets, donner le résultat de sessionInfo() peut vraiment aider. Lorsque vous parlez de connexions à d'autres applications (que ce soit par le biais de ODBC ou de toute autre solution), vous devez également fournir les numéros de version de celles-ci et, si possible, également les informations nécessaires sur la configuration.

Si vous utilisez R dans , R Studio en utilisant rstudioapi::versionInfo() peut être utile pour indiquer votre version de RStudio.

Si vous rencontrez un problème avec un paquet spécifique, vous pouvez vouloir fournir la version du paquet en donnant le résultat de packageVersion("name of the package").

1635
Joris Meys

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

Comment écrire un exemple reproductible.

Si vous fournissez un exemple reproductible, vous aurez plus de chances d’obtenir une aide efficace concernant votre problème R. Un exemple reproductible permet à une autre personne de recréer votre problème en copiant et en collant du code R.

Pour rendre votre exemple reproductible, vous devez inclure quatre éléments: packages requis, données, code et description de votre environnement R.

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

  • Le moyen le plus simple d'inclure des données dans un courrier électronique ou une question de débordement de pile est d'utiliser dput() pour générer le code R afin de le recréer. Par exemple, pour recréer le jeu de données mtcars dans R, procédez comme suit:

    1. Exécuter dput(mtcars) dans R
    2. Copier 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 vos noms de variables sont concis, mais informatifs

    • utiliser les 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 de votre code. Ceci 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 bien créé un exemple reproductible en démarrant une nouvelle session R et en collant votre script au format.

Avant de mettre tout votre code dans un email, envisagez de le mettre Gist github . Votre code sera mis en évidence par la syntaxe, sans que vous ayez à vous soucier de quoi que ce soit qui puisse être endommagé par le système de messagerie.

572
hadley

Personnellement, je préfère les doublures. Quelque chose le long des lignes:

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'auteur et non la structure exacte. J'apprécie vraiment quand les variables ne écrasent pas mes propres variables ou que dieu m'interdit, 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 package raster, vous pouvez générer des données aléatoires. La vignette du paquet contient de nombreux exemples, 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 géographique comme implémenté dans sp, vous pouvez obtenir certains jeux de données via des fichiers externes (tels que le fichier de formes ESRI) dans des packages "spatiaux" (voir la vue Spatial 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")
297
Roman Luštrik

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


INSTRUCTIONS RAPIDES

Si myData est le nom de votre objet à reproduire, exécutez ce qui suit 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 wrapper intelligent pour dput et effectue les opérations suivantes:

  • échantillonne automatiquement un grand ensemble de données (basé sur la taille et la classe. La taille de l'échantillon peut être ajustée)
  • crée une sortie dput
  • vous permet de spécifier les colonnes à exporter
  • s’ajoute devant lui objName <- ... pour qu’il soit facile à copier + coller, 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 et la coller ensuite dans 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 environ 100 x 102. Je veux échantillonner 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 sortie se trouve dans une seule ligne de Nice, pas un paragraphe de lignes hachées. Cela facilite la lecture sur SO questions et facilite également la copie et le collage.


Mise à jour d'octobre 2013:

Vous pouvez maintenant spécifier le nombre de lignes de sortie de texte à utiliser (c.-à-d. Ce que vous allez coller dans StackOverflow). Utilisez l'argument lines.out=n 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==
270
Ricardo Saporta

Voici un bon guide .

Le point le plus important est: 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 pouvez créer un petit échantillon de données ou utiliser uniquement les 10 premières lignes environ.

EDIT:

Assurez-vous également que vous avez identifié le problème vous-même. L'exemple ne doit pas être un script R complet avec "Sur la ligne 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 d'identifier le problème et de reproduire un exemple trivial dans lequel la même chose ne va pas.

189
Sacha Epskamp

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

Exemples: Parfois, il est 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 cadre de données avec 8 lignes, et trois colonnes nommées 'ligne', 'col' et 'valeur', qui ont les noms de dimension comme valeurs de 'ligne' et 'col', comme ceci:

  > x.df
     row col value
  1    A   x      1

...
(Pour 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 devriez 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: Joli code est plus facile à lire que le code laid. Utilisez un guide de style .

162
Richie Cotton

Depuis R.2.14 (je suppose), vous pouvez envoyer 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
") 
157
Paolo

Parfois, le problème n'est vraiment pas reproductible avec des données plus petites, peu importe les efforts que vous déployez, ni avec les données synthétiques (bien qu'il soit utile de montrer comment vous avez produit des ensembles de données synthétiques non reproduisez le problème, car il exclut certaines hypothèses).

  • Publier les données sur le Web quelque part et fournir une URL peut être nécessaire.
  • Si les données ne peuvent pas être divulguées au grand public mais peuvent être partagées, vous pourrez alors les envoyer par courrier électronique aux parties intéressées (bien que cela réduise le nombre de personnes qui vont se donner la peine de travailler. dessus).
  • Je ne l'ai pas encore vu, car les personnes qui ne peuvent pas divulguer leurs données sont sensibles au fait de les divulguer sous quelque forme que ce soit, mais il semblerait vraisemblable que, dans certains cas, il est possible de publier des données si elles étaient suffisamment anonymisées/brouillées/corrompues légèrement en quelque sorte.

Si vous ne pouvez pas résoudre l'un de ces problèmes, vous devrez probablement faire appel à un consultant pour résoudre votre problème ...

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

142
Ben Bolker

Les réponses à ce jour sont évidemment excellentes pour la partie reproductibilité. Il s'agit simplement de préciser qu'un exemple reproductible ne peut et ne doit pas être le seul élément d'une question. N'oubliez pas d'expliquer ce à quoi vous voulez ressembler et les contours de votre problème, pas simplement comment vous avez essayé d'y arriver jusqu'à présent. Le code ne suffit pas; vous avez aussi besoin de mots.

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


Ce qui suit est un exemple 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 ?


132
Ari B. Friedman

J'ai un moyen très facile et efficace de faire un exemple R qui n'a pas été mentionné ci-dessus. Vous pouvez définir votre structure en premier lieu. Par exemple,

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

>fix(mydata)

When you execute 'fix' command, you will get this pop-up box

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

120
jasmine_007

Pour créer rapidement un dput de vos données, vous pouvez simplement copier (un morceau 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 modifier la sep dans cette dernière si nécessaire. Cela ne fonctionnera que si vos données sont dans le presse papier bien sûr.

117
JT85

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 autant que possible votre code tout en préservant le problème/l'erreur

Cela prend un peu de travail mais semble être un compromis juste puisque vous demandez aux autres de faire le 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 jeux de données intégrés. Cela rend très facile pour les autres de travailler sur votre problème. Tapez data() à l'invite R pour voir quelles données sont disponibles. Quelques exemples classiques:

  • iris
  • mtcars
  • ggplot2::diamonds (paquet externe, mais presque tout le monde le possède)

Voir ceci SO QA pour savoir comment trouver des ensembles de données adaptés à votre problème.

Si vous pouvez reformuler votre problème en utilisant les jeux de données intégrés, vous aurez beaucoup plus de chances 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, indiquez le code R qui génère le plus petit jeu de données possible . que 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 qui essaie de répondre à ma question peut copier/coller ces deux lignes et commencer à travailler sur le problème immédiatement.

dput

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

Fournir les résultats attendus:


Quelqu'un a déjà dit:

Une image de la sortie attendue vaut 1000 mots

- une personne très sage

Si vous pouvez ajouter quelque chose comme "Je m'attendais à 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 large et difficile à manier, vous n'avez probablement pas suffisamment réfléchi à la façon de simplifier votre problème (voir ci-après).

Expliquez succinctement votre problème


La principale chose à faire est de simplifier votre problème autant que possible avant de poser votre question. Recadrer le problème pour travailler avec les jeux de données intégrés aidera beaucoup à cet égard. Vous constaterez aussi souvent qu'en procédant simplement à la simplification, vous pourrez résoudre votre propre problème.

Voici quelques exemples de bonnes questions:

Dans les deux cas, les problèmes des utilisateurs ne sont certainement pas liés aux exemples simples qu’ils fournissent. Au lieu de cela, ils ont résumé 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: utiliser des ensembles de données intégrés et fournir ce que vous attendez comme résultat 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 de débutant.

112
BrodieG

Le code reproductible est la clé pour obtenir de l'aide. Cependant, de nombreux utilisateurs peuvent être sceptiques quant au collage, même partiel. Par exemple, ils pourraient utiliser des données sensibles ou des données originales collectées pour être utilisées dans un document de recherche. Pour une raison quelconque, je pensais que ce serait bien d’avoir une fonction pratique pour "déformer" mes données avant de les coller publiquement. La fonction anonymize du paquet SciencesPo est très ridicule, mais pour moi, elle fonctionne bien avec la fonction dput.

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

Puis je 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
110
daniel

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

par exemple.,

data(mtcars)

et ensuite faire le problème

names(mtcars)
your problem demostrated on the mtcars data set
98
userJT

Si vous avez un jeu de données volumineux qu'il est difficile d'insérer dans le script à l'aide de dput(), envoyez vos données sur Pastebin et chargez-les à l'aide de read.table:

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

Inspiré par @ Henrik .

90
TMS

Je développe le package wakefield pour répondre à ce besoin de partager rapidement des données reproductibles, parfois dput fonctionne bien pour des ensembles de données plus petits, mais bon nombre des problèmes que nous traitons sont beaucoup plus vastes. Le partage d'un ensemble de données aussi volumineux via dput n'est pas pratique.

À propos de:

wakefield permet à l'utilisateur de partager un code minimal pour reproduire les données. L'utilisateur définit n (nombre de lignes) et spécifie un nombre quelconque de fonctions variables prédéfinies (il en existe actuellement 70) qui imitent des données réelles si (éléments tels que le sexe, l'âge, le revenu, etc.)

Installation:

Actuellement (2015-06-11), wakefield est un paquet GitHub mais ira à CRAN éventuellement après la rédaction 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
.. ...   ... ...    ...      ... ...    ...   ...
87
Tyler Rinker

Si vous avez une ou plusieurs variables factor dans vos données que vous souhaitez rendre reproductibles avec dput(head(mydata)), pensez à y ajouter droplevels, de sorte que les niveaux de facteurs non présents dans le jeu de données minimisé ne sont pas inclus dans votre sortie dput afin de rendre l'exemple minimal:

dput(droplevels(head(mydata)))
70
docendo discimus

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

61
CMichael

Veuillez ne pas coller vos sorties de 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")
)

Nous ne pouvons pas copier-coller directement.

Pour que les questions et réponses puissent être reproduites correctement, essayez de supprimer + & > avant de le publier et mettez # pour les sorties et les 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")

Une dernière chose, si vous avez utilisé une fonction de certains paquetages, mentionnez cette bibliothèque.

44
user2100721

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

Il existe de nombreuses façons de créer un vecteur aléatoire Créer un vecteur de 100 nombres 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 qu'il est parfois 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 vous souhaitez créer un exemple de données reproductible. Mais notez que pour rendre des données aussi représentatives que l'original (au cas où l'OP ne puisse pas partager les données d'origine), il est bon d'ajouter des informations avec l'exemple de données tel que (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 Structure 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))
30
user5947301

Vous pouvez le faire en utilisant reprex .

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

Selon Tidyverse :

Le but de "reprex" est d’empaqueter 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 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.

30
andrii

Voici certaines de mes suggestions:

  • Essayez d'utiliser les jeux de données R par défaut
  • Si vous avez votre propre jeu de données, incluez-le avec dput pour que les autres puissent vous aider plus facilement.
  • N'utilisez pas install.package() sauf si cela est vraiment nécessaire, les gens comprendront si vous utilisez simplement require ou library
  • Essayez d'être concis,

    • Avoir un ensemble de données
    • Essayez de décrire le résultat dont vous avez besoin le plus simplement 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 tracés si vous avez
  • Indiquez également toutes les erreurs que vous pourriez avoir.

Tout cela fait partie d'un exemple reproductible.

26
TheRimalaya

C'est une bonne idée d'utiliser les fonctions du paquetage testthat pour montrer ce que vous attendez. Ainsi, d'autres personnes peuvent modifier votre code jusqu'à ce qu'il s'exécute sans erreur. Cela facilite le travail de ceux qui souhaitent vous aider, car cela signifie qu'ils n'ont pas à déchiffrer 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 s'avérerait être 1,23 pour y égal ou supérieur à 10, et 3,21 sinon, mais je n'ai eu aucun résultat". Même dans cet exemple idiot, je pense que le code est plus clair que les mots. L'utilisation de testthat permet à votre assistant de se concentrer sur le code, ce qui lui permet de gagner du temps et de disposer du moyen de savoir qu'il a résolu votre problème avant de le publier.

16
dank