Como fazer um ótimo exemplo reprodutível de R

2473

Ao discutir o desempenho com colegas, ensinar, enviar um relatório de erro ou procurar orientação nas listas de discussão e aqui no Stack Overflow, um exemplo reproduzível é frequentemente solicitado e sempre útil.

Quais são as suas dicas para criar um excelente exemplo? Como você cola estruturas de dados deem formato de texto? Que outras informações você deve incluir?

Existem outros truques Além de usar dput(), dump()ou structure()? Quando você deve incluir library()ou require()declarações? Que palavras reservadas deve uma evitar, além de c, df, data, etc.?

Como alguém faz um ótimo exemplo reproduzível?

Hack-R
fonte
34
Estou confuso sobre o escopo da pergunta. As pessoas parecem ter pulado na interpretação do exemplo reproduzível ao fazer perguntas sobre SO ou R-help (como "reproduzir o erro"). E os exemplos reproduzíveis de R nas páginas de ajuda? Em demonstrações de pacotes? Em tutoriais / apresentações?
baptiste
15
@ Baptiste: O mesmo menos o erro. Todas as técnicas expliquei são usados em páginas pacote de ajuda, e em tutoriais e apresentações dou cerca de R
Joris Meys
33
Às vezes, os dados são o fator limitante, pois a estrutura pode ser muito complexa para simular. Para produzir dados públicos de dados privados: stackoverflow.com/a/10458688/742447 em stackoverflow.com/questions/10454973/...
Etienne Low-Décarie

Respostas:

1727

Um exemplo reprodutível mínimo consiste nos seguintes itens:

  • um conjunto de dados mínimo, necessário para demonstrar o problema
  • o código mínimo executável necessário para reproduzir o erro, que pode ser executado no conjunto de dados fornecido
  • as informações necessárias sobre os pacotes usados, versão R e sistema em que é executado.
  • no caso de processos aleatórios, uma semente (definida por set.seed()) para reprodutibilidade 1

Para exemplos de bons exemplos mínimos reproduzíveis , consulte os arquivos de ajuda da função que você está usando. Em geral, todo o código fornecido lá atende aos requisitos de um exemplo reproduzível mínimo: dados são fornecidos, código mínimo é fornecido e tudo é executável. Veja também as perguntas no Stack Overflow com muitas votações.

Produzindo um conjunto de dados mínimo

Na maioria dos casos, isso pode ser feito facilmente, fornecendo apenas um quadro de vetor / dados com alguns valores. Ou você pode usar um dos conjuntos de dados internos, fornecidos com a maioria dos pacotes.
Uma lista abrangente de conjuntos de dados internos pode ser vista com library(help = "datasets"). Há uma descrição curta para todos os conjuntos de dados e mais informações podem ser obtidas, por exemplo, ?mtcarsonde 'mtcars' é um dos conjuntos de dados na lista. Outros pacotes podem conter conjuntos de dados adicionais.

Fazer um vetor é fácil. Às vezes, é necessário adicionar alguma aleatoriedade a ele, e há um número inteiro de funções para fazer isso. sample()pode randomizar um vetor ou fornecer um vetor aleatório com apenas alguns valores. lettersé um vetor útil que contém o alfabeto. Isso pode ser usado para criar fatores.

Alguns exemplos:

  • valores aleatórios: x <- rnorm(10)para distribuição normal, x <- runif(10)para distribuição uniforme, ...
  • uma permutação de alguns valores: x <- sample(1:10)para o vetor 1:10 em ordem aleatória.
  • um fator aleatório: x <- sample(letters[1:4], 20, replace = TRUE)

Para matrizes, pode-se usar matrix(), por exemplo:

matrix(1:10, ncol = 2)

A criação de quadros de dados pode ser feita usando data.frame(). Deve-se prestar atenção ao nome das entradas no quadro de dados e para não torná-lo excessivamente complicado.

Um exemplo :

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

Para algumas perguntas, formatos específicos podem ser necessários. Para estes, pode-se usar qualquer um dos fornecidos as.someTypefunções: as.factor, as.Date, as.xts, ... Estes, em combinação com os truques vetor e / ou quadro de dados.

Copie seus dados

Se você tem alguns dados que seriam muito difíceis de construir usando essas dicas, então você sempre pode fazer um subconjunto de seus dados originais, usando head(), subset()ou os índices. Em seguida, use dput()para nos fornecer algo que possa ser colocado no R imediatamente:

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

Se o seu quadro de dados tiver um fator com muitos níveis, a dputsaída poderá ser difícil, pois ainda listará todos os níveis possíveis, mesmo que não estejam presentes no subconjunto dos seus dados. Para resolver esse problema, você pode usar a droplevels()função Observe abaixo como a espécie é um fator com apenas um nível:

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

Ao usar dput, você também pode incluir apenas colunas 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")

Uma outra ressalva dputé que ele não funcionará para data.tableobjetos com chave ou para agrupados tbl_df(classe grouped_df) de dplyr. Nesses casos, você pode converter novamente em um quadro de dados regular antes de compartilhar dput(as.data.frame(my_data)),.

No pior cenário, você pode fornecer uma representação de texto que pode ser lida usando o textparâ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)

Produzindo código mínimo

Essa deve ser a parte mais fácil, mas geralmente não é. O que você não deve fazer é:

  • adicione todo o tipo de conversões de dados. Verifique se os dados fornecidos já estão no formato correto (a menos que esse seja o problema, é claro)
  • copie e cole uma função / bloco inteiro de código que fornece um erro. Primeiro, tente localizar quais linhas resultam exatamente no erro. Na maioria das vezes, você descobrirá qual é o seu problema.

O que você deve fazer é:

  • adicione quais pacotes devem ser usados ​​se você usar algum (usando library())
  • se você abrir conexões ou criar arquivos, adicione algum código para fechá-las ou exclua os arquivos (usando unlink())
  • se você alterar as opções, verifique se o código contém uma instrução para revertê-las para as originais. (por exemplo op <- par(mfrow=c(1,2)) ...some code... par(op))
  • teste, execute seu código em uma nova sessão R vazia para garantir que o código possa ser executado. As pessoas devem poder copiar e colar seus dados e seu código no console e obter exatamente o mesmo que você.

Forneça informações extras

Na maioria dos casos, apenas a versão R e o sistema operacional serão suficientes. Quando surgem conflitos com pacotes, fornecer a saída de sessionInfo()pode realmente ajudar. Ao falar sobre conexões com outros aplicativos (seja através do ODBC ou qualquer outra coisa), deve-se também fornecer números de versão para esses e, se possível, também as informações necessárias sobre a instalação.

Se você estiver executando R em R Estúdio utilizando rstudioapi::versionInfo()pode ser útil para relatar sua versão rstudio.

Se você tiver um problema com um pacote específico, poderá fornecer a versão do pacote, fornecendo a saída de packageVersion("name of the package").


1 Nota: A saída de set.seed()difere entre R> 3.6.0 e versões anteriores. Especifique qual versão R você usou para o processo aleatório e não se surpreenda se obtiver resultados ligeiramente diferentes ao seguir perguntas antigas. Para obter o mesmo resultado nesses casos, você pode usar a RNGversion()função -final set.seed()(por exemplo :) RNGversion("3.5.2").

Joris Meys
fonte
6
Como você usa dputse o quadro de dados é muito grande e o problema é gerado no meio do quadro de dados? Existe uma maneira de dputreproduzir a seção intermediária de dados, digamos linhas 60 a 70?
BgnR
27
@BgnR Você pode extrair parte do quadro de dados usando índices, por exemplo: tmp <- mydf[50:70,]seguido por dput(mydf). Se o quadro de dados for realmente grande, tente isolar o problema e envie as poucas linhas que causam o problema.
Joris Meys
4
@JorisMeys: Existe uma maneira de informar headou dputlimitar os dados ao nível N recursivamente? Estou tentando criar um exemplo reproduzível e meus dados são uma lista de quadros de dados. Portanto, dput(head(myDataObj))parece não ser suficiente, pois gera um arquivo de saída com tamanho de 14 MB.
Aleksandr Blekh
5
@JorisMeys: Just FYI - postou uma pergunta no comentário acima como uma pergunta separada: stackoverflow.com/questions/25127026/… .
Aleksandr Blekh
4
@ Konrad A melhor coisa que você pode fazer é vincular o arquivo e fornecer o comando mínimo para ler esse arquivo. Isso vai ser menos problemas do que copiar-colar a saída do dput () :)
Joris Meys
590

(Aqui está o meu conselho de Como escrever um exemplo reproduzível . Tentei torná-lo curto, mas agradável)

Como escrever um exemplo reproduzível.

É mais provável que você obtenha uma boa ajuda com o seu problema de R se fornecer um exemplo reproduzível. Um exemplo reproduzível permite que outra pessoa recrie seu problema apenas copiando e colando o código R.

Há quatro coisas que você precisa incluir para tornar seu exemplo reproduzível: pacotes necessários, dados, código e uma descrição do seu ambiente R.

  • Os pacotes devem ser carregados na parte superior do script, para que seja fácil ver quais deles o exemplo precisa.

  • A maneira mais fácil de incluir dados em um email ou em uma pergunta sobre estouro de pilha é usar dput()para gerar o código R para recriá-lo. Por exemplo, para recriar o mtcarsconjunto de dados em R, execute as seguintes etapas:

    1. Executar dput(mtcars)em R
    2. Copie a saída
    3. No meu script reproduzível, digite mtcars <-e cole.
  • Gaste um pouco de tempo para garantir que seu código seja fácil para outras pessoas lerem:

    • verifique se você usou espaços e seus nomes de variáveis ​​são concisos, mas informativos

    • use comentários para indicar onde está o seu problema

    • faça o seu melhor para remover tudo o que não está relacionado ao problema.
      Quanto menor o seu código, mais fácil é entender.

  • Inclua a saída de sessionInfo()em um comentário no seu código. Isso resume seu ambiente R e facilita verificar se você está usando um pacote desatualizado.

Você pode verificar se realmente criou um exemplo reproduzível iniciando uma nova sessão R e colando seu script.

Antes de colocar todo o seu código em um email, considere colocá-lo no Gist github . Isso dará ao seu código uma boa sintaxe de destaque, e você não precisa se preocupar com nada que ocorra com o sistema de email.

hadley
fonte
24
reprexem tidyverseé um pacote bom para produzir mínima, exemplo reproduzível: github.com/tidyverse/reprex
mt1022
19
Rotineiramente, recebo e-mails com código. Até recebo e-mails com documentos do Word em anexo que contêm código. Às vezes, até recebo e-mails com documentos do Word em anexo que contêm SCREENSHOTS de código.
23418
304

Pessoalmente, eu prefiro "one" forros. Algo ao longo das linhas:

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)

A estrutura de dados deve imitar a idéia do problema do escritor e não a estrutura exata exata. Eu realmente aprecio quando variáveis ​​não sobrescrevem minhas próprias variáveis ​​ou, se Deus não proíbe, funções (como df).

Como alternativa, é possível cortar alguns cantos e apontar para um conjunto de dados pré-existente, algo como:

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

Não se esqueça de mencionar quaisquer pacotes especiais que você possa estar usando.

Se você estiver tentando demonstrar algo em objetos maiores, tente

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

Se você estiver trabalhando com dados espaciais por meio do rasterpacote, poderá gerar alguns dados aleatórios. Muitos exemplos podem ser encontrados na vinheta do pacote, mas aqui está uma pequena 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)

Se você precisar de algum objeto espacial, conforme implementado em sp, poderá obter alguns conjuntos de dados por meio de arquivos externos (como o ESRI shapefile) em pacotes "espaciais" (consulte a visualização Espacial nas exibições de tarefas).

library(rgdal)
ogrDrivers()
dsn <- system.file("vectors", package = "rgdal")[1]
ogrListLayers(dsn)
ogrInfo(dsn=dsn, layer="cities")
cities <- readOGR(dsn=dsn, layer="cities")
Roman Luštrik
fonte
1
IMHO, ao usar sampleou runifé prudente set.seed. Pelo menos, essa é a sugestão que recebi ao produzir exemplos baseados em amostragem ou geração aleatória de números.
Konrad
1
@ Konrad, eu concordo, mas isso pode depender. Se você está apenas tentando gerar alguns números, uma semente pode não ser necessária, mas se você está tentando entender algo específico onde números fixos são necessários, uma semente seria obrigatória.
Roman Luštrik
1
É sempre melhor com uma imagem inicial, facilita a comparação da própria solução com a saída esperada, a comparação de soluções entre si e, dessa forma, os usuários que não conhecem (e não precisam saber) funções como runifou samplenão estão confusos que eles não podem obter os mesmos dados.
Moody_Mudskipper
2
@ Mikey você olhou para o pacote usmap ?
Roman Luštrik 13/08/19
2
@mikey o pacote tigris de downloads shapefiles do Census Bureau em uma variedade de formatos
camilo
277

Inspirado por este post, agora uso uma função útil
reproduce(<mydata>)quando preciso postar no StackOverflow.


INSTRUÇÕES RÁPIDAS

Se myDataé o nome do seu objeto a ser reproduzido, execute o seguinte em R:

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

reproduce(myData)

Detalhes:

Essa função é um invólucro inteligente dpute faz o seguinte:

  • coleta automaticamente um grande conjunto de dados (com base no tamanho e na classe. O tamanho da amostra pode ser ajustado)
  • cria uma dputsaída
  • permite especificar quais colunas exportar
  • anexa à frente objName <- ...para que possa ser facilmente copiada + colada, mas ...
  • Se estiver trabalhando em um Mac, a saída é copiada automaticamente para a área de transferência, para que você possa simplesmente executá-lo e colar na sua pergunta.

A fonte está disponível aqui:


Exemplo:

# 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 é de cerca de 100 x 102. Quero provar 10 linhas e algumas colunas específicas

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

Fornece a seguinte saída:

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

Observe também que a totalidade da saída está em uma única linha longa e agradável, e não em um parágrafo alto de linhas cortadas. Isso facilita a leitura nas postagens das perguntas do SO e também a cópia + colar.


Atualização em outubro de 2013:

Agora você pode especificar quantas linhas de saída de texto serão ocupadas (ou seja, o que será colado no StackOverflow). Use o lines.out=nargumento para isso. Exemplo:

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

    ==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==
Ricardo Saporta
fonte
196

Aqui está um bom guia .

O ponto mais importante é: Apenas certifique-se de criar um pequeno pedaço de código que possamos executar para ver qual é o problema . Uma função útil para isso é dput(), mas se você tiver dados muito grandes, convém criar um pequeno conjunto de dados de amostra ou usar apenas as 10 primeiras linhas ou mais.

EDITAR:

Verifique também se você identificou onde está o problema. O exemplo não deve ser um script R inteiro com "Na linha 200 há um erro". Se você usar as ferramentas de depuração no R (eu amo browser()) e no Google, conseguirá realmente identificar onde está o problema e reproduzir um exemplo trivial no qual a mesma coisa dá errado.

Sacha Epskamp
fonte
165

A lista de discussão da R-help possui um guia de postagem, que abrange perguntas e respostas, incluindo um exemplo de geração de dados:

Exemplos: Às vezes, ajuda a fornecer um pequeno exemplo que alguém pode realmente executar. Por exemplo:

Se eu tiver uma matriz x da seguinte maneira:

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

como posso transformá-lo em um dataframe com 8 linhas e três colunas denominadas 'row', 'col' e 'value', que têm os nomes de dimensão como valores de 'row' e 'col', assim:

  > x.df
     row col value
  1    A   x      1

...
(Para qual a resposta pode 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")

)

A palavra pequeno é especialmente importante. Você deve procurar um exemplo reprodutível mínimo , o que significa que os dados e o código devem ser o mais simples possível para explicar o problema.

EDIT: Código bonito é mais fácil de ler do que código feio. Use um guia de estilo .

Richie Cotton
fonte
164

Desde a R.2.14 (eu acho), você pode alimentar sua representação de texto de dados diretamente para 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
") 
Paolo
fonte
3
@ sebastian-c como isso é bom para fazer exemplo reproduzível? :)
TMS
@TMS Pensando seriamente, se o solicitante forneceu os dados e o problema é pequeno (mas pode ter algumas soluções), pode ser mais rápido e você ainda pode seguir todas as etapas.
sebastian-c
146

Às vezes, o problema realmente não é reproduzível com dados menores, por mais que você tente, e não acontece com dados sintéticos (embora seja útil mostrar como você produziu conjuntos de dados sintéticos que não reproduziram o problema, porque exclui algumas hipóteses).

  • Postar os dados na Web em algum lugar e fornecer um URL pode ser necessário.
  • Se os dados não puderem ser divulgados ao público em geral, mas puderem ser compartilhados, você poderá enviá-los por e-mail para as partes interessadas (embora isso reduza o número de pessoas que se darão ao trabalho de trabalhar) nele).
  • Na verdade, eu não vi isso feito, porque as pessoas que não podem liberar seus dados são sensíveis a liberá-los de qualquer forma, mas parece plausível que, em alguns casos, ainda seja possível postar dados se forem suficientemente anonimizados / embaralhados / corrompidos levemente de algum modo.

Se você não pode fazer um desses, provavelmente precisará contratar um consultor para resolver seu problema ...

edit : Duas questões úteis para anonimização / embaralhamento:

Ben Bolker
fonte
1
Para produzir conjuntos de dados sintéticos, as respostas a esta pergunta fornecem exemplos úteis, incluindo aplicativos de fitdistre fitdistrplus.
Iterator
137

As respostas até agora são obviamente ótimas para a parte da reprodutibilidade. Isso serve apenas para esclarecer que um exemplo reproduzível não pode e não deve ser o único componente de uma pergunta. Não se esqueça de explicar como você quer que seja e os contornos do seu problema, não apenas como você tentou chegar lá até agora. Código não é suficiente; você precisa de palavras também.

Aqui está um exemplo reproduzível do que evitar fazer (extraído de um exemplo real, nomes alterados para proteger os inocentes):


A seguir, são apresentados dados de amostra e parte da função com a qual tenho problemas.

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

Como posso conseguir isso?


Ari B. Friedman
fonte
124

Eu tenho uma maneira muito fácil e eficiente de fazer um exemplo de R que não foi mencionado acima. Você pode definir sua estrutura primeiro. Por exemplo,

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

>fix(mydata)

Ao executar o comando 'fix', você receberá esta caixa pop-up

Então você pode inserir seus dados manualmente. Isso é eficiente para exemplos menores, em vez de grandes.

jasmine_007
fonte
18
... entãodput(mydata)
GSee
Qual é o seu frontend? Seria bom ter uma resposta completa. Etc cria dados que você pode fazer um loop diretamente for (d in data) {...}.
Léo Léopold Hertz 준영 30/1016
119

Para criar rapidamente um dputdos seus dados, você pode apenas copiar (um pedaço) dos dados para a área de transferência e executar o seguinte em R:

para dados no Excel:

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

para dados em um arquivo txt:

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

Você pode alterar sepo último, se necessário. Isso só funcionará se seus dados estiverem na área de transferência, é claro.

JT85
fonte
116

Diretrizes:


Seu principal objetivo ao elaborar suas perguntas deve ser o mais fácil possível para os leitores entenderem e reproduzirem o seu problema nos sistemas deles. Para fazer isso:

  1. Forneça dados de entrada
  2. Fornecer saída esperada
  3. Explique seu problema de forma sucinta
    • se você tiver mais de 20 linhas de texto + código, provavelmente poderá voltar e simplificar
    • simplifique o seu código o máximo possível, preservando o problema / erro

Isso exige algum trabalho, mas parece uma troca justa, pois você está pedindo que outras pessoas trabalhem para você.

Fornecendo dados:


Conjuntos de dados internos

A melhor opção, de longe, é confiar em conjuntos de dados internos. Isso facilita muito o trabalho de outras pessoas no seu problema. Digite data()no prompt R para ver quais dados estão disponíveis para você. Alguns exemplos clássicos:

  • iris
  • mtcars
  • ggplot2::diamonds (pacote externo, mas quase todo mundo tem)

Consulte este SO QA para saber como encontrar conjuntos de dados adequados para o seu problema.

Se você conseguir reformular seu problema para usar os conjuntos de dados internos, é muito mais provável que você obtenha boas respostas (e votos positivos).

Dados Auto-Gerados

Se o seu problema for muito específico para um tipo de dados que não está representado nos conjuntos de dados existentes, forneça o código R que gera o menor conjunto de dados possível em que o seu problema se manifesta. Por exemplo

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

Agora, alguém tentando responder à minha pergunta pode copiar / colar essas duas linhas e começar a trabalhar no problema imediatamente.

dput

Como último recurso , você pode usar dputpara transformar um objeto de dados em código R (por exemplo dput(myData)). Digo como um "último recurso", porque a saída de dputmuitas vezes é bastante pesada, irritante para copiar e colar e obscurece o restante da sua pergunta.

Fornecer saída esperada:


Alguém disse uma vez:

Uma imagem da saída esperada vale 1000 palavras

- uma pessoa muito sábia

Se você pode adicionar algo como "Eu esperava obter este resultado":

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

Na sua pergunta, é muito mais provável que as pessoas entendam rapidamente o que você está tentando fazer. Se o resultado esperado for grande e difícil de manusear, provavelmente você não pensou o suficiente sobre como simplificar o problema (veja a seguir).

Explique Seu Problema Sucintamente


A principal coisa a fazer é simplificar o seu problema o máximo possível antes de fazer sua pergunta. Re-enquadrar o problema para trabalhar com os conjuntos de dados internos ajudará muito nesse sentido. Você também encontrará frequentemente que, apenas passando pelo processo de simplificação, responderá ao seu próprio problema.

Aqui estão alguns exemplos de boas perguntas:

Nos dois casos, os problemas do usuário quase certamente não estão nos exemplos simples que eles fornecem. Em vez disso, abstraíram a natureza do problema e o aplicaram a um conjunto de dados simples para fazer sua pergunta.

Por que mais uma resposta a esta pergunta?


Esta resposta se concentra no que considero a melhor prática: use conjuntos de dados internos e forneça o que você espera como resultado de uma forma mínima. As respostas mais importantes se concentram em outros aspectos. Não espero que essa resposta se destaque; isso está aqui apenas para que eu possa vincular a ele nos comentários das perguntas dos novatos.

BrodieG
fonte
113

O código reproduzível é essencial para obter ajuda. No entanto, existem muitos usuários que podem ser céticos em colar até mesmo uma parte de seus dados. Por exemplo, eles poderiam estar trabalhando com dados confidenciais ou em dados originais coletados para uso em um trabalho de pesquisa. Por qualquer motivo, achei que seria bom ter uma função útil para "deformar" meus dados antes de colá-los publicamente. A anonymizefunção do pacote SciencesPoé muito boba, mas para mim funciona bem com a dputfunção.

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

Então eu anonimo:

> 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

Pode-se também querer amostrar poucas variáveis ​​em vez de dados completos antes de aplicar o comando anonimização e 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
daniel
fonte
102

Muitas vezes, você precisa de alguns dados para um exemplo, no entanto, não deseja postar seus dados exatos. Para usar algum data.frame existente na biblioteca estabelecida, use o comando data para importá-lo.

por exemplo,

data(mtcars)

e então faça o problema

names(mtcars)
your problem demostrated on the mtcars data set
userJT
fonte
13
Muitos conjuntos de dados internos (como conjuntos populares mtcarse de irisdados) não precisam realmente da datachamada para ser usada.
22813 Gregor Thomas
92

Se você possui um conjunto de dados grande que não pode ser facilmente colocado no script dput(), poste seus dados no pastebin e carregue-os usando read.table:

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

Inspirado por @Henrik .

TMS
fonte
90

Estou desenvolvendo o pacote wakefield para atender a essa necessidade de compartilhar dados reproduzíveis rapidamente, às vezes dputfunciona bem para conjuntos de dados menores, mas muitos dos problemas com os quais lidamos são muito maiores, o compartilhamento de um conjunto de dados tão grande por isso dputé impraticável.

Sobre:

O wakefield permite que o usuário compartilhe um código mínimo para reproduzir dados. O usuário definen(número de linhas) e especifica qualquer número de funções variáveis ​​predefinidas (atualmente existem 70) que imitam dados reais (como sexo, idade, renda etc.)

Instalação:

Atualmente (11/06/2015), wakefield é um pacote do GitHub, mas irá para o CRAN eventualmente após a gravação dos testes de unidade. Para instalar rapidamente, use:

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

Exemplo:

Aqui está um exemplo:

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

Isso produz:

    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
.. ...   ... ...    ...      ... ...    ...   ...
Tyler Rinker
fonte
72

Se você tiver uma ou mais factorvariáveis ​​em seus dados com as quais deseja reproduzir dput(head(mydata)), considere adicioná droplevels-las para que os níveis de fatores que não estão presentes no conjunto de dados minimizados não sejam incluídos em sua dputsaída, a fim de torne o exemplo mínimo :

dput(droplevels(head(mydata)))
docendo discimus
fonte
65

Gostaria de saber se um link http://old.r-fiddle.org/ poderia ser uma maneira muito interessante de compartilhar um problema. Ele recebe um ID único e pode-se pensar em incorporá-lo ao SO.

CMichael
fonte
47

Por favor, não cole as saídas do console assim:

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

Não podemos copiar e colar diretamente.

Para tornar as perguntas e respostas reproduzíveis adequadamente, tente remover +& >antes de publicá-las e colocar #para saídas e comentários 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")

Mais uma coisa, se você usou alguma função de determinado pacote, mencione essa biblioteca.

user2100721
fonte
2
você remove >e adiciona #manualmente ou existe uma maneira automática de fazer isso?
precisa saber é o seguinte
3
@BCArg removo >manualmente. Mas, além disso #, eu uso o Ctrl+Shift+Catalho no RStudioeditor.
user2100721
33

Você pode fazer isso usando reprex .

Como o mt1022 observou , "... um bom pacote para produzir um exemplo mínimo e reproduzível é " reprex " do tidyverse ".

De acordo com Tidyverse :

O objetivo do "reprex" é empacotar seu código problemático de forma que outras pessoas possam executá-lo e sentir sua dor.

Um exemplo é dado no site arrumado .

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

Eu acho que essa é a maneira mais simples de criar um exemplo reproduzível.

andrii
fonte
33

Além de todas as respostas acima que achei muito interessantes, às vezes pode ser muito fácil, conforme discutido aqui: - COMO FAZER UM EXEMPLO MÍNIMO REPRODUCÍVEL PARA AJUDAR COM R

Existem várias maneiras de criar um vetor aleatório. Crie um vetor de número 100 com valores aleatórios em R arredondado para 2 casas decimais ou matriz aleatória em R

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

Observe que, às vezes, é muito difícil compartilhar um dado dado devido a vários motivos, como dimensão etc. No entanto, todas as respostas acima são ótimas e muito importantes para pensar e usar quando se deseja fazer um exemplo de dados reproduzíveis. Mas observe que, para tornar os dados tão representativos quanto os originais (caso o OP não possa compartilhar os dados originais), é bom adicionar algumas informações com o exemplo de dados como (se chamarmos os dados de mydf1)

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

Além disso, deve-se conhecer o tipo, comprimento e atributos de um dado que pode ser uma estrutura de dados.

#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))
user5947301
fonte
28

Aqui estão algumas das minhas sugestões:

  • Tente usar conjuntos de dados R padrão
  • Se você possui seu próprio conjunto de dados, inclua-o no dput para que outros possam ajudá-lo mais facilmente
  • Não use a install.package()menos que seja realmente necessário, as pessoas entenderão se você apenas usa requireoulibrary
  • Tente ser conciso,

    • Tenha algum conjunto de dados
    • Tente descrever a saída necessária da maneira mais simples possível
    • Faça você mesmo antes de fazer a pergunta
  • É fácil fazer upload de uma imagem; portanto, faça o upload de plotagens, se você tiver
  • Inclua também quaisquer erros que você possa ter

Tudo isso faz parte de um exemplo reproduzível.

TheRimalaya
fonte
1
Você realmente não adicionou nada substancial aqui. dput()foi mencionado anteriormente e muito disso está apenas reiterando as diretrizes padrão de SO.
precisa
1
Eu estava tendo problemas com a install.packagefunção incluída no exemplo, o que não é realmente necessário (na minha opinião). Além disso, o uso do conjunto de dados R padrão tornaria a reprodução mais fácil. As diretrizes de SO não falaram nada sobre esses tópicos especificamente. Além disso, pretendia dar a minha opinião e é a que mais encontro.
TheRimalaya # 9/16
18

É uma boa ideia usar funções do testthatpacote para mostrar o que você espera que ocorra. Assim, outras pessoas podem alterar seu código até que ele seja executado sem erros. Isso facilita o fardo daqueles que gostariam de ajudá-lo, porque significa que eles não precisam decodificar sua descrição textual. Por exemplo

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

é mais claro que "eu acho que x seria 1,23 para y igual ou superior a 10 e 3,21 caso contrário, mas não obtive nenhum resultado". Mesmo neste exemplo bobo, acho que o código é mais claro do que as palavras. O uso testthatpermite que seu assistente se concentre no código, o que economiza tempo, e fornece uma maneira de saber que resolveram o seu problema antes de publicá-lo

úmido
fonte