훌륭한 R 재현 가능한 예를 만드는 방법


2473

동료들과 성능 토론, 교육, 버그 보고서 전송 또는 메일 목록 및 여기에서 스택 오버플로에 대한 지침을 검색 할 때 종종 재현 가능한 예가 요구되며 항상 도움이됩니다.

훌륭한 예를 만들기위한 팁은 무엇입니까? 데이터 구조를 붙여 넣는 방법텍스트 형식으로? 다른 정보를 포함해야합니까?

또한 거기에 다른 트릭을 사용하여인가 dput(), dump()또는 structure()? 언제 library()또는 require()진술 을 포함해야 합니까? 어떤 단어를 예약해야 하나 피하고, 추가하여 c, df, data, 등?

어떻게 위대한 사람이 되나요? 재현 가능한 예?


34
질문의 범위에 대해 혼란 스럽습니다. 사람들은 SO 또는 R- 도움말 ( "오류를 재현하는 방법")에 대한 질문을 할 때 재현 가능한 예의 해석에 뛰어 들었던 것 같습니다. 도움말 페이지에서 재현 가능한 R 예제는 어떻습니까? 패키지 데모에서? 튜토리얼 / 프레젠테이션에서?
baptiste

15
@baptiste : 오류를 뺀 것과 같습니다. 내가 설명한 모든 기술은 패키지 도움말 페이지에서 사용되며, R
Joris Meys

33
구조가 시뮬레이션하기에는 너무 복잡 할 수 있기 때문에 데이터는 때때로 제한 요소입니다. 개인 데이터에서 공개 데이터를 생성하려면 stackoverflow.com/questions/10454973/stackoverflow.com/a/10458688/742447
Etienne Low-

답변:


1727

최소한의 재현 예는 다음과 같은 항목으로 구성되어 있습니다 :

  • 문제를 보여주기 위해 필요한 최소한의 데이터 셋
  • 주어진 데이터 셋에서 실행될 수있는 오류를 재현하는 데 필요한 최소한의 실행 가능한 코드
  • 사용 된 패키지, R 버전 및 실행되는 시스템에 대한 필수 정보
  • 랜덤 프로세스의 경우, set.seed()재현성을위한 시드 (에 의해 설정 됨 ) 1

좋은 예는 최소한의 재현 예 , 당신이 사용하고있는 함수의 도움말 파일을 참조하십시오. 일반적으로 여기에 제공된 모든 코드는 최소한의 재현 가능한 예 (데이터 제공, 최소 코드 제공 및 모든 실행 가능)의 요구 사항을 충족합니다. 또한 업 보트가 많은 스택 오버플로에 대한 질문을 살펴보십시오.

최소 데이터 세트 생성

대부분의 경우 일부 값을 가진 벡터 / 데이터 프레임 만 제공하면 쉽게 수행 할 수 있습니다. 또는 대부분의 패키지와 함께 제공되는 내장 데이터 세트 중 하나를 사용할 수 있습니다.
내장 데이터 세트의 전체 목록은에서 확인할 수 있습니다 library(help = "datasets"). 모든 데이터 세트에 대한 간단한 설명이 있으며, 예를 들어 ?mtcars'mtcars'가 목록의 데이터 세트 중 하나 인 경우 더 많은 정보를 얻을 수 있습니다 . 다른 패키지에는 추가 데이터 세트가 포함될 수 있습니다.

벡터를 만드는 것은 쉽습니다. 때로는 임의성을 추가해야 할 필요가 있으며,이를 수행하기위한 수많은 기능이 있습니다. sample()벡터를 랜덤 화하거나 소수의 값으로 랜덤 벡터를 제공 할 수 있습니다. letters알파벳을 포함하는 유용한 벡터입니다. 요인을 만드는 데 사용할 수 있습니다.

몇 가지 예 :

  • 임의의 값 : x <- rnorm(10)정규 분포, x <- runif(10)균일 분포, ...
  • 일부 값의 순열 : x <- sample(1:10) 벡터 1:10의 경우 무작위 순서.
  • 임의의 요인 : x <- sample(letters[1:4], 20, replace = TRUE)

행렬의 경우 다음과 같이 사용할 수 있습니다 matrix().

matrix(1:10, ncol = 2)

사용하여 데이터 프레임 만들기 data.frame() . 데이터 프레임의 항목 이름을 지정하고 지나치게 복잡하게 만들지 않도록주의해야합니다.

예 :

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

일부 질문에는 특정 형식이 필요할 수 있습니다. 이 경우, 하나는 제공의 사용할 수있는 as.someType기능을 : as.factor, as.Date,as.xts 벡터 및 / 또는 데이터 프레임 트릭와 함께, ...이 있습니다.

데이터 복사

이 팁을 사용하여 구성하기 어려운 데이터가있는 경우 head(), subset()또는 인덱스를 사용하여 항상 원본 데이터의 하위 집합을 만들 수 있습니다 . 그런 다음 dput()R에 즉시 넣을 수있는 것을 제공하십시오.

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

데이터 프레임에 여러 수준의 요인이있는 dput경우 데이터의 하위 집합에 존재하지 않더라도 가능한 모든 요인 수준이 여전히 나열되므로 출력이 다루기 어려울 수 있습니다. 이 문제를 해결하기 위해이 droplevels()기능을 사용할 수 있습니다 . 종이 한 수준으로 만 작용하는 요소는 다음과 같습니다.

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

를 사용할 때 dput관련 항목 만 포함 할 수도 있습니다.

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

다른주의 사항 dput은 키가있는 data.table객체 나 그룹화 된 tbl_df(클래스 grouped_df) 에는 작동하지 않는다는 것입니다 dplyr. 이 경우 공유하기 전에 일반 데이터 프레임으로 다시 변환 할 수 있습니다 dput(as.data.frame(my_data)).

최악의 시나리오는 다음 text매개 변수를 사용하여 읽을 수있는 텍스트 표현을 제공 할 수 있습니다 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)

최소한의 코드 생성

이것은 쉬운 부분이어야하지만 종종 그렇지 않습니다. 하지 말아야 할 것은 :

  • 모든 종류의 데이터 변환을 추가하십시오. 제공된 데이터가 올바른 형식인지 확인하십시오 (물론 문제가 아닌 한)
  • 전체 함수 / 코드 덩어리를 복사하여 붙여 넣으면 오류가 발생합니다. 먼저 오류가 발생한 줄을 찾으십시오. 종종 문제가 무엇인지 알게 될 것입니다.

당신이해야 할 일은 :

  • 사용하는 패키지를 추가하십시오 (을 사용하여 library())
  • 연결을 열거 나 파일을 만드는 경우 코드를 추가하여 닫거나 파일을 삭제하십시오 ( unlink())
  • 옵션을 변경하는 경우 코드에 원래 상태로 되 돌리는 명령문이 코드에 포함되어 있는지 확인하십시오. (예를 들어 op <- par(mfrow=c(1,2)) ...some code... par(op))
  • 새로운 빈 R 세션에서 코드를 테스트 실행하여 코드를 실행할 수 있는지 확인하십시오. 사람들은 콘솔에서 데이터와 코드를 복사하여 붙여 넣을 수 있고 정확히 동일한 것을 얻을 수 있습니다.

추가 정보 제공

대부분의 경우 R 버전과 운영 체제로 충분합니다. 패키지와 충돌이 발생하면 출력을주는 것이 sessionInfo()실제로 도움 이 될 수 있습니다. 다른 응용 프로그램 (ODBC 등을 통한 연결)에 대한 연결에 대해 이야기 할 때는 해당 응용 프로그램의 버전 번호와 가능한 경우 설정에 대한 정보도 제공해야합니다.

R Studio 에서 R을 사용 하는 경우 rstudioapi::versionInfo()RStudio 버전을보고하는 데 도움이 될 수 있습니다.

특정 패키지에 문제가있는 경우의 출력을 제공하여 패키지 버전을 제공 할 수 있습니다 packageVersion("name of the package").


1 참고 : 출력은 set.seed()R> 3.6.0과 이전 버전간에 다릅니다. 랜덤 프로세스에 사용한 R 버전을 지정하고 이전 질문을 따를 때 약간 다른 결과가 나오는 경우 놀라지 마십시오. 이러한 경우에 동일한 결과를 얻으려면 RNGversion()전에 -function을 사용하면됩니다 set.seed()(예 :) RNGversion("3.5.2").


6
dput데이터 프레임이 매우 크고 데이터 프레임 중간에 문제가 발생 하는 경우 어떻게 사용 합니까? dput60-70 행과 같은 데이터의 중간 부분을 재현 하는 방법이 있습니까?
BgnR

27
@BgnR tmp <- mydf[50:70,]다음 과 같은 인덱스를 사용하여 데이터 프레임의 일부를 추출 할 수 있습니다 dput(mydf). 데이터 프레임이 실제로 큰 경우 문제를 찾아보고 문제를 일으키는 몇 줄만 제출하십시오.
Joris Meys

4
@JorisMeys : 재귀 적으로 데이터를 N 레벨 로 말 head하거나 dput제한 하는 방법이 있습니까? 재현 가능한 예제를 만들려고하는데 내 데이터는 데이터 프레임 목록입니다. 따라서 dput(head(myDataObj))14MB 크기의 출력 파일을 생성하므로 충분하지 않은 것 같습니다.
Aleksandr Blekh

5
@JorisMeys : 위의 주석에서 FYI 게시 된 질문은 별도의 질문으로 stackoverflow.com/questions/25127026/… .
Aleksandr Blekh

4
@Konrad 당신이 할 수있는 가장 좋은 것은 파일에 링크하고 해당 파일에서 읽을 최소한의 명령을 내리는 것입니다. dput () :)의 출력을 복사하여 붙여 넣는 것보다 덜 번거로울 것입니다.
Joris Meys

589

(여기 에 재현 가능한 예제를 작성하는 방법에 대한 조언이 있습니다 . 짧지 만 달콤하게 만들려고 노력했습니다)

재현 가능한 예를 작성하는 방법.

재현 가능한 예제를 제공하면 R 문제에 대한 도움을받을 가능성이 높습니다. 재현 가능한 예제를 통해 다른 사람이 R 코드를 복사하여 붙여 넣기 만하면 문제를 재현 할 수 있습니다.

예제를 재현하기 위해 포함해야 할 필수 패키지, 데이터, 코드 및 R 환경에 대한 설명이 있습니다.

  • 패키지 는 스크립트 상단에로드되어야하므로 예제에 필요한 패키지 를 쉽게 확인할 수 있습니다.

  • 이메일 또는 스택 오버플로 질문에 데이터 를 포함하는 가장 쉬운 방법 dput()은 R 코드를 생성하여 다시 생성하는 것입니다. 예를 들어 mtcarsR 에서 데이터 집합 을 다시 만들 려면 다음 단계를 수행합니다.

    1. dput(mtcars)R에서 실행
    2. 출력 복사
    3. 재현 가능한 스크립트에 다음을 입력하십시오. mtcars <- 한 후 붙여 넣기를 수행하십시오.
  • 약간의 시간을 보내십시오. 다른 사람들이 쉽게 코드 를 읽을 수 십시오.

    • 공백을 사용하고 변수 이름이 간결하지만 정보를 제공하는지 확인하십시오.

    • 주석을 사용하여 문제가있는 위치를 나타냅니다.

    • 문제와 관련이없는 모든 것을 제거하기 위해 최선을 다하십시오.
      코드가 짧을수록 이해하기 쉽습니다.

  • sessionInfo()코드에 주석에 출력을 포함시킵니다 . 여기에는 R 환경 이 요약되어 있으며 오래된 패키지를 사용하고 있는지 쉽게 확인할 수 있습니다.

새로운 R 세션을 시작하고 스크립트를 붙여 넣어 실제로 재현 가능한 예를 만들 었는지 확인할 수 있습니다.

모든 코드를 전자 메일에 넣기 전에 Gist github 에 넣으십시오 . 코드에 멋진 구문 강조 표시를 제공하며 전자 메일 시스템으로 인해 엉망이되는 것에 대해 걱정할 필요가 없습니다.


24
reprextidyverse: 최소한의 재현 예를 생산하는 좋은 패키지입니다 github.com/tidyverse/reprex
mt1022

19
나는 일상적으로 코드가 포함 된 이메일을받습니다. 코드가 포함 된 첨부 된 워드 문서가 포함 된 이메일도 수신합니다. 때로는 SCREENSHOTS 코드가 포함 된 첨부 된 워드 문서가 포함 된 전자 메일을받을 수도 있습니다.
hadley

304

개인적으로 저는 "한"라이너를 선호합니다. 라인을 따라 뭔가 :

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)

데이터 구조는 정확한 축어 구조가 아니라 작가의 문제에 대한 아이디어를 모방해야합니다. 변수가 내 변수를 덮어 쓰지 않거나 신 금지 된 기능 (예 :df .

또는 몇 가지 모서리를 잘라내어 기존 데이터 세트를 가리킬 수 있습니다.

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

사용중인 특별 패키지를 언급하는 것을 잊지 마십시오.

더 큰 물체에서 무언가를 보여주고 싶다면 시도해보십시오.

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

raster패키지 를 통해 공간 데이터로 작업하는 경우 임의의 데이터를 생성 할 수 있습니다. 패키지 비 ign 트에서 많은 예제를 찾을 수 있지만 여기에는 작은 덩어리가 있습니다.

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)

에 구현 된 일부 공간 객체가 필요한 경우 sp"공간"패키지의 외부 파일 (예 : ESRI shapefile)을 통해 일부 데이터 세트를 가져올 수 있습니다 (작업보기의 공간보기 참조).

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

1
IMHO는 사용할 때 sample또는 runif신중합니다 set.seed. 적어도 샘플링 또는 난수 생성에 대한 릴레이 예제를 생성 할 때받은 제안입니다.
Konrad

1
@ Konrad 동의하지만, 이것은 다를 수 있습니다. 일부 숫자를 생성하려는 경우 시드가 필요하지 않을 수 있지만 고정 숫자가 필요한 특정 항목을 이해하려는 경우 시드가 필수입니다.
로마 루스 트리 크

1
시드 imo를 사용하는 것이 항상 더 낫습니다. 자신의 솔루션을 예상 출력과 비교하고 자신 간의 솔루션을 쉽게 비교할 수 있습니다. 이러한 방식으로 기능을 모르 runif거나 sample혼동하지 않는 사용자 동일한 데이터를 얻을 수 없습니다.
Moody_Mudskipper

2
@ mikey usmap 패키지 를 보셨습니까 ?
Roman Luštrik

2
@mikey 패키지 tigris 는 인구 조사국에서 다양한 형식으로 shapefile을 다운로드합니다.
camille

277

이 게시물에서 영감을 받아 이제
reproduce(<mydata>)StackOverflow에 게시해야 할 때 편리한 기능을 사용합니다 .


빠른 지침

myData재현 할 오브젝트의 이름 인 경우 R에서 다음을 실행하십시오.

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

reproduce(myData)

세부:

이 기능은 지능형 래퍼 dput이며 다음을 수행합니다.

  • 큰 데이터 세트를 자동으로 샘플링합니다 (크기 및 클래스를 기준으로합니다. 샘플 크기를 조정할 수 있음)
  • 를 만듭니다 dput출력을
  • 당신은 지정할 수 있는 수출에 열을
  • 그것의 앞에 추가 objName <- ...쉽게 복사 + 붙여 넣을 수 있도록 하지만 ...
  • Mac에서 작업하는 경우 출력이 자동으로 클립 보드에 복사되므로 간단히 실행 한 다음 질문에 붙여 넣을 수 있습니다.

출처는 다음과 같습니다.


예:

# 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는 약 100 x 102입니다. 10 개의 행과 몇 개의 특정 열을 샘플링하고 싶습니다.

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

다음과 같은 출력을 제공합니다.

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

또한 출력의 전체가 잘게 잘린 줄의 큰 단락이 아닌 멋진 한 줄로되어 있습니다. 따라서 SO 질문 게시물을보다 쉽게 ​​읽을 수 있으며 복사 / 붙여 넣기도 더 쉽습니다.


2013 년 10 월 업데이트 :

이제 몇 줄의 텍스트 출력을 취할 것인지 (즉, StackOverflow에 붙여 넣을 내용)를 지정할 수 있습니다. 사용lines.out=n 인수를 . 예:

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

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

196

여기 좋은 가이드가 있습니다.

가장 중요한 요점은 다음과 같습니다 . 문제가 무엇인지 확인할 수있는 작은 코드를 만들어야합니다 . 유용한 기능은입니다 dput(). 그러나 데이터가 매우 큰 경우 작은 샘플 데이터 세트를 만들거나 처음 10 개 라인 만 사용하는 것이 좋습니다.

편집하다:

또한 문제가 어디에 있는지 확인하십시오. 예를 들어 "온라인 200 오류가있는"전체 R 스크립트가 아니어야합니다. R (I love browser()) 및 Google 에서 디버깅 도구를 사용하면 실제로 문제가있는 곳을 식별하고 똑같은 문제가 발생하는 사소한 예를 재현 할 수 있어야합니다.


165

R-help 메일 링리스트에는 데이터 생성 예를 포함하여 질문과 대답을 모두 다루는 게시 안내서 가 있습니다.

예 : 때로는 누군가가 실제로 실행할 수있는 작은 예를 제공하는 데 도움이됩니다. 예를 들면 다음과 같습니다.

다음과 같이 행렬 x가있는 경우 :

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

다음과 같이 8 개의 행과 'row', 'col'및 'value'라는 3 개의 열이있는 데이터 프레임으로 변환하는 방법은 다음과 같이 차원 이름이 'row'및 'col'입니다.

  > x.df
     row col value
  1    A   x      1

...
(답은 다음과 같습니다.

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

)

단어 작은 가 특히 중요합니다. 최소한의 재현 가능한 예를 목표로 해야합니다. 즉, 문제를 설명하기 위해 데이터와 코드가 가능한 한 단순해야합니다.

편집 : 예쁜 코드는 못생긴 코드보다 읽기 쉽습니다. 스타일 가이드를 사용하십시오 .


164

R.2.14부터 (데이터 추측)에 데이터 텍스트 표현을 직접 공급할 수 있습니다 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
") 

3
@ sebastian-c 어떻게 재현 가능한 예제를 만드는 데 좋은가요? :)
TMS

@TMS 심각하게 생각하면, asker가 데이터를 제공했고 문제가 작지만 (몇 가지 해결책이있을 수 있음) 더 빠를 수 있으며 모든 단계를 계속 수행 할 수 있습니다.
sebastian-c

146

아무리 노력해도 아무리 작은 데이터로도 문제를 재현 할 수없고 합성 데이터에서는 발생하지 않는 경우가 있습니다 ( 문제를 재현 하지 않은 합성 데이터 세트를 생성 한 방법을 보여주는 것이 유용하지만) 그것은 몇 가지 가설을 배제한다).

  • 웹에 데이터를 게시하고 URL을 제공해야 할 수 있습니다.
  • 데이터를 대중에게 공개 할 수는 없지만 전혀 공유 할 수없는 경우, 관심있는 당사자에게 전자 메일을 보내도록 제안 할 수 있습니다 (이로 인해 작업을 귀찮게하는 사람들의 수가 줄어들지 만) 그 위에).
  • 데이터를 공개 할 수없는 사람들이 데이터를 공개하는 것에 민감하기 때문에 실제로는이 작업을 수행하지 못했습니다. 그러나 일부 경우에는 데이터가 충분히 익명화 / 스크램블링 / 손상된 경우 여전히 데이터를 게시 할 수있는 것으로 보입니다. 어떤 식 으로든.

이 중 하나를 수행 할 수없는 경우 문제를 해결하기 위해 컨설턴트를 고용해야합니다.

편집 : 익명화 / 스크램블링에 대한 두 가지 유용한 SO 질문 :


1
합성 데이터 세트를 생성 할 때이 질문에 대한 답변fitdistr및의 응용 프로그램을 포함한 유용한 예를 제공합니다 fitdistrplus.
반복자

137

지금까지의 대답은 분명히 재현성 부분에 좋습니다. 이것은 재현 가능한 예가 질문의 유일한 구성 요소가 될 수 없으며 그렇게해서는 안된다는 것을 명확히하기위한 것입니다. 지금까지 시도한 방법뿐만 아니라 원하는 모양과 문제의 윤곽을 설명하는 것을 잊지 마십시오. 코드가 충분하지 않습니다. 당신은 또한 단어가 필요합니다.

피해야 할 일에 대한 재현 가능한 예는 다음과 같습니다 (실제 예에서 도출, 무고한 사람들을 보호하기 위해 이름이 변경됨).


다음은 샘플 데이터 및 문제가있는 기능의 일부입니다.

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

어떻게하면 되나요?



124

위에서 언급하지 않은 R 예제를 만드는 매우 쉽고 효율적인 방법이 있습니다. 먼저 구조를 정의 할 수 있습니다. 예를 들어

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

>fix(mydata)

'fix'명령을 실행하면이 팝업 상자가 나타납니다.

그런 다음 데이터를 수동으로 입력 할 수 있습니다. 큰 예제보다는 작은 예제에 효율적입니다.


18
... 그럼dput(mydata)
G 16:14의

프론트 엔드는 무엇입니까? 완전한 답을 얻는 것이 좋을 것입니다. 등은 직접 루프 할 수있는 데이터를 만듭니다 for (d in data) {...}.
Léo Léopold Hertz 준영

119

빠르게 만들려면 dput데이터 데이터를 클립 보드에 복사 (일부)하고 R에서 다음을 실행하면됩니다.

Excel 데이터의 경우 :

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

txt 파일의 데이터 :

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

sep필요한 경우 후자를 변경할 수 있습니다 . 데이터가 물론 클립 보드에있는 경우에만 작동합니다.


116

지침 :


질문을 작성하는 데있어 주된 목표는 독자가 자신의 시스템에서 문제를 이해하고 재현 할 수 있도록 가능한 한 쉽게 만드는 것입니다. 그렇게하려면 :

  1. 입력 데이터 제공
  2. 예상 출력 제공
  3. 간결하게 문제를 설명하십시오
    • 20 줄 이상의 텍스트 + 코드가 있다면 아마도 돌아가서 단순화 할 수 있습니다.
    • 문제 / 오류를 유지하면서 코드를 최대한 단순화

이것은 약간의 작업이 필요하지만 다른 사람들이 당신을 위해 일하도록 요구하기 때문에 공정한 절충안처럼 보입니다.

데이터 제공 :


내장 데이터 세트

지금까지 가장 좋은 방법 은 내장 데이터 세트에 의존하는 것입니다. 이를 통해 다른 사람들이 귀하의 문제에 대해 쉽게 작업 할 수 있습니다. data()R 프롬프트에 입력 하여 사용 가능한 데이터를 확인하십시오. 몇 가지 고전적인 예 :

  • iris
  • mtcars
  • ggplot2::diamonds (외부 패키지이지만 거의 모든 사람이 가지고 있음)

문제에 적합한 데이터 세트를 찾는 방법 은이 SO QA 를 참조하십시오 .

내장 데이터 세트를 사용하도록 문제를 다시 표현할 수 있다면 좋은 답변을 얻을 가능성이 훨씬 높습니다.

자체 생성 데이터

문제점이 기존 데이터 세트에 표시되지 않은 데이터 유형에 매우 특정한 경우 문제점이 표시하는 가능한 가장 작은 데이터 세트를 생성하는 R 코드를 제공하십시오 . 예를 들어

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

이제 내 질문에 대답하려고하는 사람이 그 두 줄을 복사 / 붙여 넣기하고 즉시 문제를 해결할 수 있습니다.

A와 최후의 수단 , 당신이 사용할 수있는 dputR 코드 (예 :에 데이터 오브젝트를 변환 dput(myData)). 나는 "마지막 수단"이라고 말합니다.dput 상당히 다루기 어렵고 복사하여 붙여 넣기를 성가 시게하고 나머지 질문을 모호하게하기 때문입니다.

예상 결과 제공 :


누군가가 한 번 말했다 :

예상되는 출력의 그림은 1000 단어의 가치가 있습니다.

-매우 현명한 사람

"이 결과를 기대합니다"와 같은 것을 추가 할 수 있다면 :

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

귀하의 질문에, 사람들은 당신이하려는 일을 빨리 이해할 가능성이 훨씬 높습니다. 예상되는 결과가 크고 다루기 힘든 경우 문제를 단순화하는 방법에 대해 충분히 생각하지 못했을 것입니다 (다음 참조).

간결하게 문제를 설명하십시오


가장 먼저해야 할 일은 질문하기 전에 가능한 한 문제를 단순화하는 것입니다. 내장 데이터 세트로 작업하기 위해 문제를 재구성하면 이와 관련하여 많은 도움이 될 것입니다. 또한 단순화 과정을 거치는 것만으로도 자신의 문제에 답할 수 있다는 것을 알게 될 것입니다.

다음은 좋은 질문의 예입니다.

두 경우 모두, 사용자의 문제는 그들이 제공하는 간단한 예제와 거의 관련이 없습니다. 오히려 문제의 본질을 추상화하여 간단한 데이터 세트에 적용하여 질문을했습니다.

왜이 질문에 또 다른 답이 있습니까?


이 답변은 내가 생각하는 가장 좋은 방법에 중점을 둡니다. 내장 데이터 세트를 사용하고 최소한의 결과로 예상되는 것을 제공하십시오. 가장 눈에 띄는 답변은 다른 측면에 중점을 둡니다. 나는이 대답이 어느 정도 눈에 띄는 것으로 기대하지는 않는다. 이것은 초보자 질문에 대한 의견으로 링크 할 수 있도록 여기에 있습니다.


113

재현 가능한 코드는 도움을 얻기위한 열쇠입니다. 그러나 많은 양의 데이터를 붙여 넣는 것에 회의적 일 수있는 많은 사용자가 있습니다. 예를 들어, 민감한 데이터를 다루거나 연구 논문에 사용하기 위해 수집 된 원본 데이터로 작업 할 수 있습니다. 어떤 이유로 든, 데이터를 공개적으로 붙여 넣기 전에 데이터를 "변형"하는 편리한 기능을 갖는 것이 좋을 것이라고 생각했습니다. anonymize패키지 의 기능 SciencesPo은 매우 어리석지 만 나를 위해 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

그런 다음 익명으로 처리합니다.

> 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

익명화 및 dput 명령을 적용하기 전에 전체 데이터 대신 몇 가지 변수를 샘플링 할 수도 있습니다.

    # sample two variables without replacement
> anonymize(sample.df(dt,5,vars=c("Y","X")))
   Y    X
1 a1 -0.4
2 a1  0.6
3 a2 -2.4
4 a1 -1.4
5 a2  3.6

102

그러나 예를 들어 일부 데이터가 필요한 경우가 있지만 정확한 데이터를 게시하고 싶지는 않습니다. 설정된 라이브러리에서 일부 기존 data.frame을 사용하려면 data 명령을 사용하여 가져 오십시오.

예를 들어

data(mtcars)

그런 다음 문제를 해결하십시오

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

13
많은 내장 (인기와 같은 데이터 세트 mtcarsiris데이터 세트) 실제로 필요하지 않습니다 data사용하는 전화.
Gregor Thomas

92

를 사용하여 스크립트에 쉽게 넣을 수없는 큰 데이터 세트가있는 경우 dput()데이터를 pastebin에 게시 하고 다음을 사용하여로드하십시오 read.table.

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

@Henrik에서 영감을 얻었습니다 .


90

나는 재현 가능한 데이터를 신속하게 공유 해야하는 필요성을 해결 하기 위해 wakefield 패키지 를 개발 중이며 때로는 dput작은 데이터 세트에서는 잘 작동하지만 우리가 다루는 많은 문제는 훨씬 더 커져서 큰 데이터 세트를 통해 공유합니다.dput 것은 비현실적입니다.

약:

wakefield를 통해 사용자는 최소한의 코드를 공유하여 데이터를 재생할 수 있습니다. 사용자 설정n (행 수)를 설정하고 실제 if 데이터 (성별, 연령, 수입 등)를 모방하는 사전 설정 변수 함수 (현재 70 개)를 지정합니다.

설치:

현재 (2015-06-11) wakefield 는 GitHub 패키지이지만 단위 테스트가 작성된 후 CRAN으로 이동합니다. 빠르게 설치하려면 다음을 사용하십시오.

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

예:

예를 들면 다음과 같습니다.

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

이것은 다음을 생성합니다.

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

72

factor데이터에 재현 할 수있는 하나 이상의 변수 가있는 경우 최소화 된 데이터 세트에없는 요인 수준이 출력에 포함되지 않도록 변수를 dput(head(mydata))추가 droplevels하는 것이 좋습니다. dput예제를 최소화하십시오 .

dput(droplevels(head(mydata)))


47

다음과 같이 콘솔 출력을 붙여 넣지 마십시오.

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

직접 복사하여 붙여 넣을 수는 없습니다.

질문과 답변을 제대로 재현 할 수있게하려면 게시하기 전에 +& 를 삭제 >하고 다음과 #같이 출력과 주석을 넣으십시오 .

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

한 가지 더, 특정 패키지의 함수를 사용한 경우 해당 라이브러리를 언급하십시오.


2
를 제거하고 수동으로 >추가 #합니까, 아니면 자동으로 수행 할 수 있습니까?
BCArg

3
@BCArg >수동으로 제거 합니다. 그러나의 추가를 위해 편집기 에서 바로 가기를 #사용 합니다. Ctrl+Shift+CRStudio
user2100721

33

reprex를 사용 하여이 작업을 수행 할 수 있습니다 .

으로 mt1022 지적 ... "최소한의 재현 예를 생산하는 좋은 패키지는, "reprex " 에서 tidyverse ".

Tidyverse 에 따르면 :

"reprex"의 목표는 다른 사람들이 코드를 실행하고 고통을 느낄 수있는 방식으로 문제가되는 코드를 패키지화하는 것입니다.

tidyverse 웹 사이트 에 예가 있습니다.

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

이것이 재현 가능한 예제를 만드는 가장 간단한 방법 이라고 생각합니다 .


33

내가 매우 흥미롭게 찾은 위의 모든 대답 외에도 여기에서 논의되는 것처럼 때로는 매우 쉽습니다 .- R로 도움을 얻는 최소의 재현 가능한 예 를 만드는 방법

임의의 벡터를 만드는 방법에는 여러 가지가 있습니다. R의 소수점 이하 자릿수 2로 반올림 하거나 R의 임의 행렬로 100 개의 숫자 벡터를 만듭니다.

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

차원 등과 같은 여러 가지 이유로 인해 주어진 데이터를 공유하는 것이 매우 어려운 경우가 있습니다. 그러나 위의 모든 대답은 재현 가능한 데이터 예제를 만들고 싶을 때 생각하고 사용하는 것이 매우 중요합니다. 그러나 데이터를 원본과 같이 대표적으로 만들려면 (OP가 원본 데이터를 공유 할 수없는 경우) 다음과 같이 데이터 예제에 일부 정보를 추가하는 것이 좋습니다 (데이터를 mydf1이라고하는 경우).

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

또한 데이터 구조 가 될 수있는 데이터 의 유형, 길이 및 속성을 알아야합니다.

#found based on the following 
typeof(mydf1), what it is.
length(mydf1), how many elements it contains.
attributes(mydf1), additional arbitrary metadata.

#If you cannot share your original data, you can str it and give an idea about the structure of your data
head(str(mydf1))

28

내 제안 중 일부는 다음과 같습니다.

  • 기본 R 데이터 세트를 사용하십시오.
  • 자신의 데이터 세트가있는 경우 dput 다른 사람들이 더 쉽게 도울 수 있도록하십시오.
  • 사용하지 마십시오 install.package()그냥 사용하는 경우 정말 필요한 경우가 아니면, 사람들이 이해 requirelibrary
  • 간결하고

    • 일부 데이터 세트를 가지고
    • 필요한 결과물을 가능한 한 간단하게 설명하십시오
    • 질문하기 전에 스스로해라
  • 이미지를 쉽게 업로드 할 수 있으므로
  • 또한 발생할 수있는 모든 오류를 포함하십시오

이 모든 것은 재현 가능한 예의 일부입니다.


1
여기에 물질을 전혀 넣지 않았습니다. dput()앞에서 언급 한 바 있으며이 중 많은 부분이 표준 SO 지침을 반복합니다.
Rich Scriven

1
install.package실제로 필요하지 않은 예제에 포함 된 기능에 문제가있었습니다 (제 의견으로는). 또한 기본 R 데이터 세트를 사용하면 재현이 쉬워집니다. SO 지침은 이러한 주제에 대해 구체적으로 언급하지 않았습니다. 또한, 그것은 내 의견을 제시하기위한 것이며 이것들은 내가 가장 많이 만난 것입니다.
TheRimalaya

18

testthat패키지의 함수를 사용하여 예상되는 결과를 표시하는 것이 좋습니다. 따라서 다른 사람들이 오류없이 실행될 때까지 코드를 변경할 수 있습니다. 이렇게하면 텍스트 설명을 해독 할 필요가 없기 때문에 도움을 원하는 사람들의 부담이 줄어 듭니다. 예를 들어

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

"나는 x가 y와 같거나 10을 초과하는 경우 1.23이 될 것이고 그렇지 않으면 3.21이 될 것이라고 생각하지만 결과는 없습니다." 이 어리석은 예에서도 코드가 단어보다 명확하다고 생각합니다. 를 사용 testthat하면 도우미가 코드에 집중하여 시간을 절약 할 수 있으며 문제를 게시하기 전에 문제가 해결되었음을 알 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.