優れたRの再現可能な例を作る方法


2473

同僚とパフォーマンスについて話し合ったり、指導したり、バグレポートを送信したり、メーリングリストやここStack Stackflowでガイダンスを検索したりする場合再現可能な例がよく尋ねられ、常に役立ちます。

優れた例を作成するためのヒントは何ですか?からデータ構造を貼り付ける方法テキスト形式で?他にどのような情報を含める必要がありますか?

dput()dump()またはを使用することに加えて他のトリックはありstructure()ますか?library()or require()ステートメントはいつ含める必要がありますか?言葉1つの避けなければならない、に加えて予約されたcdfdata、などを?

どうすれば素晴らしい 再現可能な例?


34
質問の範囲について混乱しています。人々は、SOまたはR-help(「エラーの再現方法」)について質問する際に、再現可能な例の解釈に飛びついたようです。ヘルプページの再現可能なRの例はどうですか?パッケージデモでは?チュートリアル/プレゼンテーションでは?
バプティスト2011

15
@baptiste:同じマイナスのエラー。私が説明したすべての手法は、パッケージのヘルプページ、およびRについて説明するチュートリアルやプレゼンテーションで使用されています
Joris Meys

33
構造が複雑すぎてシミュレーションできない場合があるため、データが制限要因になる場合があります。プライベートデータから公開データを生成するには、次のstackoverflow.com/a/10458688/742447stackoverflow.com/questions/10454973/...
エティエンヌ低Décarie

回答:


1727

最小の再現の例では、以下の項目で構成されています。

  • 問題を実証するために必要な最小限のデータセット
  • エラーを再現するために必要な最小限の実行可能コード。これは、特定のデータセットで実行できます
  • 使用されたパッケージ、Rバージョン、およびそれが実行されるシステムに関する必要な情報。
  • ランダムプロセスの場合、set.seed()再現性のシード(によって設定)1

良い例については、最小限の再現性の例は、使用している機能のヘルプファイルを参照してください。一般的に、そこに記載されているすべてのコードは、最小限の再現可能な例の要件を満たしています。データが提供され、最小限のコードが提供され、すべてが実行可能です。また、多数の賛成票があるStack Overflowの質問もご覧ください。

最小限のデータセットを作成する

ほとんどの場合、これは、いくつかの値を持つベクター/データフレームを提供するだけで簡単に実行できます。または、ほとんどのパッケージで提供されている組み込みデータセットのいずれかを使用できます。
組み込みのデータセットの包括的なリストは、で確認できますlibrary(help = "datasets")。すべてのデータセットに短い説明があり、たとえば?mtcars「mtcars」がリスト内のデータセットの1つである場合などに、より多くの情報を取得できます。他のパッケージには、追加のデータセットが含まれている場合があります。

ベクトルを作るのは簡単です。時々それにランダム性を追加する必要があり、それを行うための関数がたくさんあります。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)
)

一部の質問では、特定の形式が必要になる場合があります。これらの場合、1は、提供のいずれかを使用することができますas.someType:関数as.factoras.Dateas.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()関数を使用できます。種が1つのレベルのみを持つ因子であることを以下に示します。

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

のもう1つの警告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 StudioRを実行している場合、を使用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データフレームが非常に大きく、問題がデータフレームの中央で発生した場合、どのように使用しますか?dputデータの中間セクションを再現するために使用する方法はありますか?たとえば、行60から70までです。
BgnR 2014

27
あなたはインデックスを使用して、データフレームの一部を抽出することができ@BgnR、例えば:tmp <- mydf[50:70,]続きますdput(mydf)。データフレームが本当に大きい場合は、問題を切り分けて、問題の原因となる数行を送信してください。
Joris Meys 2014

4
@JorisMeys:データをレベルNに再帰的に通知headまたはdput制限する方法はありますか?私は再現可能な例を考え出そうとしていますが、私のデータはデータフレームのリストです。したがって、dput(head(myDataObj))14MBサイズの出力ファイルが生成されるため、十分ではないようです。
Aleksandr Blekh 2014

5
@JorisMeys:Just FYI-別の質問として上のコメントに投稿された質問:stackoverflow.com/questions/25127026/…
Aleksandr Blekh 2014

4
@Konradあなたができる最善のことは、ファイルにリンクし、そのファイルを読み取るための最小限のコマンドを与えることです。それは、dput()の出力をコピーして貼り付けるよりも面倒が少ないでしょう:)
Joris Meys

590

再現可能な例を書く方法からのアドバイスです。短くて甘いものにしようとしました)

再現可能な例の書き方。

再現可能な例を提供すれば、Rの問題をうまく解決できるでしょう。再現可能な例では、誰かがRコードをコピーして貼り付けるだけで問題を再現できます。

サンプルを再現可能にするには、必要なパッケージ、データ、コード、R環境の説明の4つを含める必要があります。

  • パッケージはスクリプトの先頭にロードする必要があるため、例に必要なパッケージを簡単に確認できます。

  • メールまたはスタックオーバーフローの質問にデータを含める最も簡単な方法は、を使用dput()してRコードを生成し、それを再作成することです。たとえばmtcars、Rでデータセットを再作成するには、次の手順を実行します。

    1. dput(mtcars)Rで実行
    2. 出力をコピーする
    3. 私の再現可能なスクリプトで、入力してmtcars <-貼り付けます。
  • 少し時間をかけて、他のユーザーがコードを読みやすくなるようにします。

    • スペースを使用していることと、変数名が簡潔であることを確認してください。

    • コメントを使用して、問題のある場所を示します

    • 問題に関連しないすべてのものを削除するために最善を尽くしてください。
      コードが短いほど、理解しやすくなります。

  • sessionInfo()コードのコメントにの出力を含めます。これはR環境を要約したもので、古いパッケージを使用しているかどうかを簡単に確認できます。

新しいRセッションを開始してスクリプトを貼り付けることで、実際に再現可能な例が作成されたことを確認できます。

すべてのコードをメールに入れる前に、Gist githubに置くことを検討してください。それはあなたのコードに良い構文強調を与えます、そしてあなたは電子メールシステムによって壊される何かについて心配する必要はありません。


24
reprexin tidyverseは最小限の再現可能な例を作成するのに適したパッケージです:github.com/tidyverse/reprex
mt1022

19
コードを含むメールを定期的に受け取ります。コードを含むワードドキュメントが添付されたメールを受信することさえできます。コードのスクリーンショットを含むワードドキュメントが添付されたメールを受け取ることもあります。
ハドリー2018年

304

個人的には、「1枚」のライナーを好みます。線に沿った何か:

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パッケージを介して空間データを操作している場合は、ランダムデータを生成できます。多くの例がパッケージビネットにありますが、ここに小さなナゲットがあります。

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シェイプファイルなど)を介していくつかのデータセットを取得できます(タスクビューの空間ビューを参照)。

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

1
私見、使用するとき、sampleまたはrunifそれは賢明set.seedです。少なくとも、これは、サンプリングまたは乱数生成を中継する例を作成するときに受け取った提案です。
Konrad

1
@Konrad私は同意しますが、これは依存する場合があります。いくつかの数値を生成するだけの場合、シードは必要ない場合がありますが、固定数が必要な特定のことを理解しようとする場合、シードは必須です。
RomanLuštrik18年

1
それはそれが簡単に自分たちの間でソリューションを比較するために、期待される出力に独自のソリューションを比較することができ、IMOシードで常により良いですし、知らない(と知っている必要はありません)この方法は、ユーザーのような機能runifsample混同されていません同じデータを取得できないこと。
Moody_Mudskipper 2018

2
@mikeyあなたはusmapパッケージを見ましたか?
RomanLuštrik19年

2
@mikeyパッケージtigrisは、国勢調査局からさまざまな形式でシェープファイルをダウンロードします
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(私は大好きです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つの列を持ちます。

  > 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それを真剣に考えて、質問者がデータを提供し、問題が小さい場合(ただし、いくつかの解決策がある場合)、それはより高速であり、すべての手順に従うことができます。
sebastian-c 2014

146

時々 、問題は、実際にデータの小さな作品は、あなたがしよういかに難しいかを問わずと再現性がない、そしてそれはあなたがた合成データセット生成方法を示すために便利ですが、(合成データでは発生しませんではない問題を再現しているため、一部の仮説は除外されます)。

  • データをどこかにWebに投稿し、URLを提供する必要がある場合があります。
  • データを一般に公開することはできないが、まったく共有できる場合は、関係者に電子メールで送信することを提案できる場合があります(ただし、これにより、面倒な作業を行う人の数が減ります。その上)。
  • データをリリースできない人はどのような形でもデータをリリースすることに敏感なので、実際にこれが行われたのを見たことはありませんが、場合によっては、データが十分に匿名化/スクランブル/わずかに破損している場合でも、データを投稿できる可能性があります何らかの方法で。

これらのいずれも実行できない場合は、問題を解決するためにコンサルタントを雇う必要があるでしょう...

編集:匿名化/スクランブルのための2つの便利な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)

「修正」コマンドを実行すると、このポップアップボックスが表示されます

その後、手動でデータを入力できます。これは、大きな例よりも小さな例の場合に効率的です。


18
...その後dput(mydata)
GSee 2014年

あなたのフロントエンドは何ですか?完全な答えがあればいいのですが。等のように直接ループできるデータを作成しますfor (d in data) {...}
レオ・レオポルド・ヘルツ준 영

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

これで、私の質問に答えようとする人が、これらの2行をコピー/貼り付けして、問題の処理をすぐに開始できます。

dput

最後の手段として、を使用dputしてデータオブジェクトをRコードに変換できます(などdput(myData))。の出力dputはしばしば扱いにくく、コピーして貼り付けるのが面倒で、残りの質問を不明瞭にするため、「最後の手段」と言います。

期待される出力を提供する:


誰かがかつて言った:

予想される出力の画像は1000ワードの価値があります

-非常に賢い人

「私はこの結果を得ることを期待していた」のようなものを追加できる場合:

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

あなたの質問に対して、人々はあなたが何をしようとしているのかをすぐに理解する可能性がはるかに高くなります。予想される結果が大きく扱いにくい場合は、問題を単純化する方法について十分に考えていません(次を参照)。

問題を簡潔に説明する


主なことは、質問する前に問題をできるだけ単純化することです。組み込みのデータセットで動作するように問題を再構成すると、この点で多くの助けになります。また、単純化のプロセスを実行するだけで、自分の問題に答えられることもよくあります。

良い質問の例をいくつか示します。

どちらの場合も、ユーザーの問題は、ほとんどの場合、ユーザーが提供する単純な例には当てはまりません。むしろ、彼らは問題の性質を抽象化し、それを単純なデータセットに適用して質問をしました。

なぜこの質問に対するもう1つの答えですか?


この回答は、私がベストプラクティスだと思うことに焦点を当てています。組み込みのデータセットを使用し、最小限のフォームで結果として期待される結果を提供します。最も顕著な答えは他の側面に焦点を当てています。私はこの答えが目立つようになることを期待していません。これは、初心者の質問へのコメントでリンクできるようにするためだけにあります。


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呼び出しを使用する必要はありません。
グレゴールトーマス


90

私はウェイクフィールドパッケージを開発して、再現可能なデータをすばやく共有するというこのニーズに対処します。dput小さいデータセットではうまく機能することもありますが、私たちが扱う問題の多くははるかに大きく、そのような大きなデータセットを共有することdputは現実的ではありません。

約:

wakefieldにより、ユーザーは最小限のコードを共有してデータを再現できます。ユーザーはn(行数)を設定し、実際のデータ(性別、年齢、収入など)を模倣するプリセット変数関数(現在70個あります)をいくつでも指定します

インストール:

現在(2015年6月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再現可能にするデータに1つ以上の変数がある場合は、変数にdput(head(mydata))追加droplevelsすることを検討してください。これにより、最小化されたデータセットに存在しない因子のレベルがdput出力に含まれないようにして、例を最小限にしてください:

dput(droplevels(head(mydata)))

65

http://old.r-fiddle.org/リンクが問題を共有するための非常にきちんとした方法であるかどうか疑問に思います。のような一意のIDを受け取り、SOに埋め込むことも考えられます。


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

もう1つ、特定のパッケージの関数を使用した場合は、そのライブラリについて言及します。


2
を削除し>#手動で追加しますか、それを行う自動方法はありますか?
BCArg 2017

3
@BCArg >手動で削除します。しかし、の追加のために、エディターでショートカット#を使用します。Ctrl+Shift+CRStudio
user2100721 2017

33

これはreprexを使用して行うことができます。

以下のようmt1022が指摘し、「...良いパッケージを最小限に製造するために、再現性のある例はある『reprex』からtidyverse」。

Tidyverseによると:

「reprex」の目的は、問題のあるコードを他の人が実行して痛みを感じるような方法でパッケージ化することです。

例は、tidyverse Webサイトに記載されています。

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

これは、再現可能な例を作成する最も簡単な方法だと思います。


33

それは、ここで説明するように離れて、私は非常に興味深い見つけた答え上記のすべての、それは時には非常に簡単なことができます: - Rのヘルプを表示するための最低限の再現性の例を作成する方法

ランダムベクトルが作るには多くの方法があります2つの小数に丸めRのランダムな値で100番号のベクトルを作成しますが、 Rまたはランダム行列

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.