Como fazer um ótimo exemplo R reproduzível
Ao discutir desempenho com colegas, ensinar, enviar um relatório de bug ou buscar orientação em listas de e-mail e aqui no Stack Overflow, um exemplo reproduzível é frequentemente solicitado e sempre útil.
Quais são suas dicas para criar um excelente exemplo? Como você cola estruturas de dados de r em um 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 declarações library()
ou require()
? Que palavras reservadas deve uma evitar, além de c
, df
, data
, etc.?
Como é que se faz um grande r exemplo reproduzível?
Respostas
Um exemplo mínimo reproduzível 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 obter 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 atende aos requisitos de um exemplo reproduzível mínimo: os dados são fornecidos, o código mínimo é fornecido e tudo é executável. Veja também as perguntas no Stack Overflow com muitos votos positivos.
Produzindo um conjunto mínimo de dados
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 integrados, que são fornecidos com a maioria dos pacotes.
Uma lista abrangente de conjuntos de dados integrados pode ser vista com library(help = "datasets")
. Há uma breve descrição para cada conjunto de dados e mais informações podem ser obtidas, por exemplo, ?mtcars
onde 'mtcars' é um dos conjuntos de dados na lista. Outros pacotes podem conter conjuntos de dados adicionais.
Criar um vetor é fácil. Às vezes é necessário adicionar alguma aleatoriedade a ele, e há um grande número de funções para fazer isso. sample()
pode tornar um vetor aleatório ou fornecer um vetor aleatório com apenas alguns valores. letters
é um vetor útil que contém o alfabeto. Isso pode ser usado para fazer 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 nomear as entradas no quadro de dados e 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 questões, formatos específicos podem ser necessários. Para estes, pode-se usar qualquer um dos fornecidos as.someType
funçõ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 dar algo que pode ser colocado em 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 dput
saída pode ser complicada porque ainda listará todos os níveis de fator possíveis, mesmo se eles não estiverem presentes no subconjunto de 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 querer 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 não funcionará para data.table
objetos com chave ou para agrupados tbl_df
(classe grouped_df
) de dplyr
. Nestes casos, você pode converter de volta para um quadro de dados regular antes de compartilhar dput(as.data.frame(my_data))
.
Na pior das hipóteses, você pode fornecer uma representação de texto que pode ser lida usando o text
parâmetro de read.table
:
zz <- "Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa"
Data <- read.table(text=zz, header = TRUE)
Produção de código mínimo
Essa deveria ser a parte fácil, mas geralmente não é. O que você não deve fazer é:
- adicione todos os tipos de conversões de dados. Certifique-se de que os dados fornecidos já estejam no formato correto (a menos que esse seja o problema, é claro)
- copiar e colar uma função / pedaço de código inteiro que apresenta um erro. Primeiro, tente localizar quais linhas resultam exatamente no erro. Na maioria das vezes, você mesmo descobrirá qual é o 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á-los ou exclua os arquivos (usando
unlink()
) - se você alterar as opções, certifique-se de que o código contém uma instrução para reverter para os originais. (por exemplo
op <- par(mfrow=c(1,2)) ...some code... par(op)
) - teste execute seu código em uma sessão R nova e vazia para certificar-se de que o código pode ser executado. As pessoas devem ser capazes de apenas copiar e colar seus dados e seu código no console e obter exatamente o mesmo que você.
Dê 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. Quando se fala em conexões com outros aplicativos (seja através de ODBC ou qualquer outro), deve-se também fornecer os números das versões dos mesmos e, se possível, também as informações necessárias sobre a configuraçã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 o resultado 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 em tais casos, você pode usar a RNGversion()
função-antes set.seed()
(por exemplo :) RNGversion("3.5.2")
.
(Aqui está meu conselho em Como escrever um exemplo reproduzível . Tentei ser curto, mas agradável)
Como escrever um exemplo reproduzível.
É mais provável que você obtenha uma boa ajuda com 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 de seu ambiente R.
Os pacotes devem ser carregados no início do script, para que seja fácil ver de quais deles o exemplo precisa.
A maneira mais fácil de incluir dados em um e-mail ou pergunta do Stack Overflow é usar
dput()
para gerar o código R para recriá-lo. Por exemplo, para recriar omtcars
conjunto de dados em R, realizaria as seguintes etapas:- Executar
dput(mtcars)
em R - Copie o resultado
- No meu script reproduzível, digite
mtcars <-
e cole.
- Executar
Gaste um pouco de tempo garantindo que seu código seja fácil de ler:
certifique-se de usar espaços e os nomes de suas variáveis são concisos, mas informativos
use comentários para indicar onde está o seu problema
faça o possível para remover tudo o que não está relacionado ao problema.
Quanto mais curto for o código, mais fácil será de entender.
Inclua a saída de
sessionInfo()
em um comentário em seu código. Isso resume seu ambiente R e torna mais fácil 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 e-mail, considere colocá-lo no github do Gist . Isso dará ao seu código um bom realce de sintaxe, e você não precisa se preocupar se nada será interrompido pelo sistema de e-mail.
Pessoalmente, prefiro forros "um". Algo nesse sentido:
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 ideia do problema do escritor e não a estrutura exata literal. Eu realmente aprecio quando as variáveis não sobrescrevem minhas próprias variáveis ou Deus me livre, funções (como df
).
Como alternativa, pode-se 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ê está tentando demonstrar algo em objetos maiores, você pode tentar
my.df2 <- data.frame(a = sample(10e6), b = sample(letters, 10e6, replace = TRUE))
Se você estiver trabalhando com dados espaciais por meio do raster
pacote, 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 precisar de algum objeto espacial conforme implementado no sp
, você pode obter alguns conjuntos de dados por meio de arquivos externos (como o arquivo de forma ESRI) em pacotes "espaciais" (consulte a visualização Espacial em Visualizaçõ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")
Inspirado por esta mesma postagem, agora uso uma função útil
reproduce(<mydata>)
quando preciso postar no StackOverflow.
INSTRUÇÕES RÁPIDAS
Se myData
for o nome do seu objeto a reproduzir, execute o seguinte em R:
install.packages("devtools")
library(devtools)
source_url("https://raw.github.com/rsaporta/pubR/gitbranch/reproduce.R")
reproduce(myData)
Detalhes:
Esta função é um wrapper inteligente para dput
e faz o seguinte:
- amostra automaticamente um grande conjunto de dados (com base no tamanho e classe. O tamanho da amostra pode ser ajustado)
- cria uma
dput
saída - permite que você especifique quais colunas exportar
- anexa na frente dele
objName <- ...
para que possa ser facilmente copiado e colado, mas ... - Se estiver trabalhando em um mac, a saída será copiada automaticamente para a área de transferência, para que você possa simplesmente executá-la e colar na sua pergunta.
A fonte está disponível aqui:
- Github - pubR / reproduce.R
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 tem cerca de 100 x 102. Quero amostrar 10 linhas e algumas colunas específicas
reproduce(DF, cols=c("id", "X1", "X73", "Class")) # I could also specify the column number.
Dá 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, não em um parágrafo alto de linhas cortadas. Isso torna mais fácil ler as postagens de perguntas do SO e também copiar e colar.
Atualização em outubro de 2013:
Agora você pode especificar quantas linhas de saída de texto ocupará (ou seja, o que você colará no StackOverflow). Use o lines.out=n
argumento 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==
Aqui está um bom guia .
O ponto mais importante é: apenas certifique-se de fazer um pequeno trecho 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, pode querer fazer um pequeno conjunto de dados de amostra ou usar apenas as primeiras 10 linhas ou mais.
EDITAR:
Além disso, certifique-se de identificar 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 em R (adoro browser()
) e no Google, deve ser capaz de realmente identificar onde está o problema e reproduzir um exemplo trivial em que a mesma coisa dá errado.
A lista de e-mails R-help tem um guia de postagem que cobre tanto fazer quanto responder a perguntas, 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 forma:
> 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 chamadas 'linha', 'col' e 'valor', que têm os nomes das dimensões como os valores de 'linha' e 'col', assim:
> x.df
row col value
1 A x 1
...
(para o 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 ter como objetivo um exemplo reproduzí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: um código bonito é mais fácil de ler do que um código feio. Use um guia de estilo .
Desde 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
")
Às vezes, o problema realmente não é reproduzível com um dado menor, não importa o quanto 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).
- Publicar os dados em algum lugar da web e fornecer um URL pode ser necessário.
- Se os dados não puderem ser liberados para o público em geral, mas puderem ser compartilhados, você poderá se oferecer para enviá-los por e-mail às partes interessadas (embora isso reduza o número de pessoas que se preocuparão em trabalhar nele).
- Na verdade, eu não vi isso ser feito, porque as pessoas que não podem liberar seus dados são sensíveis ao liberá-los de qualquer forma, mas parece plausível que em alguns casos ainda seja possível postar dados se forem anonimizados / embaralhados / corrompidos o suficiente de algum modo.
Se você não puder fazer nada disso, provavelmente precisará contratar um consultor para resolver seu problema ...
editar : Duas perguntas úteis do SO para anonimato / embaralhamento:
- Como criar um conjunto de dados de exemplo a partir de dados privados (substituindo nomes de variáveis e níveis por espaços reservados não informativos)?
- Dado um conjunto de números aleatórios retirados de uma distribuição univariada contínua, encontre a distribuição
As respostas até agora são obviamente ótimas para a parte de reprodutibilidade. Isso é 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ê deseja que seja e os contornos do seu problema, não apenas como você tentou chegar lá até agora. Código não é suficiente; você também precisa de palavras.
Aqui está um exemplo reproduzível do que evitar fazer (tirado de um exemplo real, nomes alterados para proteger os inocentes):
A seguir estão 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?
Eu tenho uma maneira muito fácil e eficiente de fazer um exemplo R que não foi mencionada acima. Você pode definir sua estrutura em primeiro lugar. Por exemplo,
mydata <- data.frame(a=character(0), b=numeric(0), c=numeric(0), d=numeric(0))
>fix(mydata)
Em seguida, você pode inserir seus dados manualmente. Isso é eficiente para exemplos menores em vez de grandes.
Para criar rapidamente um dput
dos seus dados, você pode simplesmente copiar (um pedaço) dos dados para a sua área de transferência e executar o seguinte em R:
para dados em 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 sep
o último, se necessário. Isso só funcionará se seus dados estiverem na área de transferência, é claro.
Diretrizes:
Seu principal objetivo ao elaborar suas perguntas deve ser tornar o mais fácil possível para os leitores compreender e reproduzir seu problema em seus sistemas. Para fazer isso:
- Fornece dados de entrada
- Fornece a saída esperada
- Explique seu problema sucintamente
- se você tem mais de 20 linhas de texto + código, você provavelmente pode 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, já que você está pedindo a outros que façam o trabalho para você.
Fornecendo dados:
Conjuntos de dados integrados
De longe, a melhor opção é contar com conjuntos de dados integrados. Isso torna muito mais fácil para outras pessoas trabalharem em 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)
Inspecione os conjuntos de dados integrados para encontrar um adequado para o seu problema.
Se você for capaz de reformular seu problema para usar os conjuntos de dados integrados, é muito mais provável que obtenha boas respostas (e votos positivos).
Dados Autogerados
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 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 dput
para transformar um objeto de dados em código R (por exemplo dput(myData)
). Digo como um "último recurso" porque a saída de dput
muitas vezes é bastante difícil de manejar, irritante de copiar e colar e obscurece o resto da sua pergunta.
Fornece o resultado esperado:
Alguém disse uma vez:
Uma imagem de saída esperada vale 1000 palavras
- uma pessoa muito sábia
Se você puder adicionar algo como "Eu esperava obter este resultado":
cyl mean.hp
1: 6 122.28571
2: 4 82.63636
3: 8 209.21429
à sua pergunta, as pessoas têm muito mais probabilidade de entender rapidamente o que você está tentando fazer. Se o resultado esperado for grande e difícil de manejar, provavelmente você não pensou o suficiente sobre como simplificar seu problema (veja a seguir).
Explique seu problema de forma sucinta
A principal coisa a fazer é simplificar o seu problema o máximo possível antes de fazer sua pergunta. Reestruturar o problema para trabalhar com os conjuntos de dados integrados ajudará muito nesse aspecto. Freqüentemente, você também descobrirá que, apenas passando pelo processo de simplificação, responderá ao seu próprio problema.
Aqui estão alguns exemplos de boas perguntas:
- com conjunto de dados integrado
- com dados gerados pelo usuário
Em ambos os casos, os problemas do usuário quase certamente não estão nos exemplos simples que eles fornecem. Em vez disso, eles abstraíram a natureza de seu problema e o aplicaram a um conjunto de dados simples para fazer suas perguntas.
Por que mais uma resposta a esta pergunta?
Esta resposta enfoca o que eu acho que é a prática recomendada: use conjuntos de dados integrados e forneça o que você espera como resultado de uma forma mínima. As respostas mais proeminentes enfocam outros aspectos. Não espero que essa resposta ganhe destaque; ele está aqui apenas para que eu possa criar um link para ele em comentários a perguntas de novatos.
Código reproduzível é a chave para obter ajuda. No entanto, muitos usuários podem ser céticos em relação a colar até mesmo uma parte de seus dados. Por exemplo, eles podem estar trabalhando com dados confidenciais ou em dados originais coletados para uso em um artigo de pesquisa. Por qualquer motivo, achei que seria bom ter uma função útil para "deformar" meus dados antes de colá-los publicamente. A anonymize
função do pacote SciencesPo
é muito boba, mas para mim funciona bem com a dput
funçã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 anonimizo:
> anonymize(dt)
Z X Y
1 b2 2.5 c1
2 b6 -4.5 c2
3 b3 1.5 c1
4 b4 0.5 c1
5 b7 -3.5 c1
6 b1 4.5 c2
7 b9 -0.5 c1
8 b5 3.5 c2
9 b8 -1.5 c2
10 b10 -2.5 c1
Pode-se também querer amostrar algumas variáveis em vez de todos os dados antes de aplicar o anonimato e o comando dput.
# sample two variables without replacement
> anonymize(sample.df(dt,5,vars=c("Y","X")))
Y X
1 a1 -0.4
2 a1 0.6
3 a2 -2.4
4 a1 -1.4
5 a2 3.6
Freqüentemente, 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 resolva o problema
names(mtcars)
your problem demostrated on the mtcars data set
Se você tiver um grande conjunto de dados que não pode ser facilmente colocado no script usando 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 .
Estou desenvolvendo o pacote wakefield para atender a essa necessidade de compartilhar rapidamente dados reproduzíveis; às vezes dput
funciona bem para conjuntos de dados menores, mas muitos dos problemas com os quais lidamos são muito maiores, compartilhar um conjunto de dados tão grande via dput
é impraticável.
Sobre:
wakefield permite ao usuário compartilhar 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 GitHub, mas irá para o CRAN eventualmente depois que os testes de unidade forem escritos. 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
.. ... ... ... ... ... ... ... ...
Se você tiver uma ou mais factor
variáveis em seus dados que deseja tornar reproduzíveis dput(head(mydata))
, considere adicioná droplevels
-las, de modo que os níveis de fatores que não estão presentes no conjunto de dados minimizado não sejam incluídos em sua dput
saída, a fim de faça o exemplo mínimo :
dput(droplevels(head(mydata)))
Eu me pergunto se um http://old.r-fiddle.org/o link pode ser uma maneira muito bacana de compartilhar um problema. Ele recebe um ID único como e pode-se até pensar em incorporá-lo ao SO.
Não cole as saídas do console desta forma:
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 postá-las e colocá-las #
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.
Você pode fazer isso usando o reprex .
Como mt1022 observou , "... um bom pacote para produzir um exemplo mínimo reproduzível é " reprex " do tidyverse ".
De acordo com o 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 tidyverse .
library(reprex)
y <- 1:4
mean(y)
reprex()
Acho que essa é a maneira mais simples de criar um exemplo reproduzível.
Além de todas as respostas acima, que achei muito interessantes, às vezes pode ser muito fácil, como é discutido aqui: - COMO FAZER UM EXEMPLO REPRODUÍVEL MÍNIMO PARA OBTER AJUDA COM R
Existem muitas maneiras de fazer um vetor aleatório Crie um vetor de 100 números com valores aleatórios em R arredondados para 2 casas decimais ou uma 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ível. Mas observe que, para tornar um dado tão representativo quanto o original (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 saber o tipo, comprimento e atributos de um dado que pode ser Estruturas 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))
Aqui estão algumas das minhas sugestões:
- Tente usar conjuntos de dados R padrão
- Se você tiver seu próprio conjunto de dados, inclua-os com
dput
, para que outras pessoas possam ajudá-lo mais facilmente - Não use a
install.package()
menos que seja realmente necessário, as pessoas entenderão se você apenas usarrequire
oulibrary
Tente ser conciso,
- Tem algum conjunto de dados
- Tente descrever a saída de que você precisa da maneira mais simples possível
- Faça você mesmo antes de fazer a pergunta
- É fácil fazer upload de uma imagem, então faça upload de plotagens, se você tiver
- Inclua também quaisquer erros que possa ter
Tudo isso faz parte de um exemplo reproduzível.
É uma boa ideia usar funções do testthat
pacote para mostrar o que você espera que ocorra. Assim, outras pessoas podem alterar seu código até que ele seja executado sem erros. Isso alivia 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 do que "Acho que x resultaria em 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. Usar testthat
permite que seu ajudante se concentre no código, o que economiza tempo e fornece uma maneira de eles saberem que resolveram seu problema, antes de publicá-lo