Cara membuat contoh R yang bagus yang bisa direproduksi

2473

Ketika mendiskusikan kinerja dengan kolega, mengajar, mengirim laporan bug atau mencari panduan tentang milis dan di sini di Stack Overflow, contoh yang direproduksi sering ditanyakan dan selalu membantu.

Apa tips Anda untuk membuat contoh yang bagus? Bagaimana Anda menempelkan struktur datadalam format teks? Informasi apa lagi yang harus Anda sertakan?

Apakah ada trik lain selain menggunakan dput(), dump()atau structure()? Kapan Anda harus memasukkan library()atau require()pernyataan? Mana kata-kata dicadangkan harus satu menghindari, di samping c, df, data, dll?

Bagaimana cara membuat yang hebat contoh yang direproduksi?

Hack-R
sumber
34
Saya bingung tentang ruang lingkup pertanyaan. Orang-orang tampaknya telah melompat pada interpretasi contoh yang direproduksi dalam mengajukan pertanyaan pada SO atau R-help (bagaimana "mereproduksi kesalahan"). Bagaimana dengan contoh R yang dapat direproduksi dalam halaman bantuan? Dalam demo paket? Dalam tutorial / presentasi?
baptiste
15
@aptapte: Sama minus kesalahannya. Semua teknik yang saya jelaskan digunakan dalam halaman bantuan paket, dan dalam tutorial dan presentasi saya berikan tentang R
Joris Meys
33
Data terkadang merupakan faktor pembatas, karena struktur mungkin terlalu rumit untuk disimulasikan. Untuk menghasilkan data publik dari data pribadi: stackoverflow.com/a/10458688/742447 di stackoverflow.com/questions/10454973/...
Etienne Low-Décarie

Jawaban:

1727

Contoh minimal yang dapat direproduksi terdiri dari item berikut:

  • dataset minimal, diperlukan untuk menunjukkan masalah
  • kode runnable minimal yang diperlukan untuk mereproduksi kesalahan, yang dapat dijalankan pada dataset yang diberikan
  • informasi yang diperlukan tentang paket-paket yang digunakan, versi R, dan sistem yang dijalankannya.
  • dalam hal proses acak, benih (ditetapkan oleh set.seed()) untuk reproduktifitas 1

Untuk contoh contoh minimal yang dapat direproduksi dengan baik , lihat file bantuan dari fungsi yang Anda gunakan. Secara umum, semua kode yang diberikan di sana memenuhi persyaratan contoh minimal yang dapat direproduksi: data disediakan, kode minimal disediakan, dan semuanya dapat dijalankan. Lihat juga pertanyaan tentang Stack Overflow dengan banyak upvotes.

Menghasilkan dataset minimal

Untuk sebagian besar kasus, ini dapat dengan mudah dilakukan dengan hanya menyediakan beberapa vektor / bingkai data dengan beberapa nilai. Atau Anda dapat menggunakan salah satu dataset bawaan, yang disediakan dengan sebagian besar paket.
Daftar lengkap dataset bawaan dapat dilihat bersama library(help = "datasets"). Ada deskripsi singkat untuk setiap dataset dan informasi lebih lanjut dapat diperoleh misalnya dengan di ?mtcarsmana 'mtcars' adalah salah satu dataset dalam daftar. Paket lain mungkin berisi set data tambahan.

Membuat vektor itu mudah. Terkadang perlu untuk menambahkan keacakan, dan ada sejumlah fungsi untuk membuatnya. sample()dapat mengacak vektor, atau memberikan vektor acak dengan hanya beberapa nilai. lettersadalah vektor yang berguna yang mengandung alfabet. Ini dapat digunakan untuk membuat faktor.

Beberapa contoh:

  • nilai acak: x <- rnorm(10)untuk distribusi normal, x <- runif(10)untuk distribusi seragam, ...
  • permutasi beberapa nilai: x <- sample(1:10)untuk vektor 1:10 dalam urutan acak.
  • faktor acak: x <- sample(letters[1:4], 20, replace = TRUE)

Untuk matriks, seseorang dapat menggunakan matrix(), misalnya:

matrix(1:10, ncol = 2)

Pembuatan frame data bisa dilakukan dengan menggunakan data.frame(). Orang harus memperhatikan nama entri dalam bingkai data, dan tidak membuatnya terlalu rumit.

Sebuah contoh :

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

Untuk beberapa pertanyaan, format spesifik dapat diperlukan. Untuk ini, seseorang dapat menggunakan salah satu yang disediakan as.someTypefungsi: as.factor, as.Date, as.xts, ... ini dalam kombinasi dengan vektor dan / atau data frame trik.

Salin data Anda

Jika Anda memiliki beberapa data yang akan terlalu sulit dibangun menggunakan tips ini, maka Anda selalu dapat membuat subset dari data asli Anda, menggunakan head(), subset()atau indeks. Kemudian gunakan dput()untuk memberi kita sesuatu yang dapat dimasukkan ke dalam R segera:

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

Jika bingkai data Anda memiliki faktor dengan banyak level, dputoutput dapat menjadi berat karena masih akan mencantumkan semua tingkat faktor yang mungkin bahkan jika mereka tidak hadir dalam subset data Anda. Untuk mengatasi masalah ini, Anda dapat menggunakan droplevels()fungsi ini. Perhatikan di bawah ini bagaimana spesies merupakan faktor dengan hanya satu tingkat:

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

Saat menggunakan dput, Anda mungkin hanya ingin memasukkan kolom yang relevan:

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

Satu peringatan lain dputadalah bahwa itu tidak akan berfungsi untuk data.tableobjek yang dikunci atau untuk dikelompokkan tbl_df(kelas grouped_df) dari dplyr. Dalam kasus ini, Anda dapat mengonversi kembali ke bingkai data biasa sebelum berbagi dput(as.data.frame(my_data)),.

Skenario terburuk, Anda dapat memberikan representasi teks yang dapat dibaca dengan menggunakan textparameter 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)

Memproduksi kode minimal

Ini harus menjadi bagian yang mudah tetapi seringkali tidak. Yang tidak boleh Anda lakukan adalah:

  • tambahkan semua jenis konversi data. Pastikan data yang diberikan sudah dalam format yang benar (kecuali tentu saja itu masalah)
  • copy-paste seluruh fungsi / potongan kode yang memberikan kesalahan. Pertama, coba cari baris mana yang menyebabkan galat. Lebih sering daripada tidak Anda akan menemukan apa masalahnya sendiri.

Yang harus Anda lakukan adalah:

  • tambahkan paket mana yang harus digunakan jika Anda menggunakan (menggunakan library())
  • jika Anda membuka koneksi atau membuat file, tambahkan beberapa kode untuk menutupnya atau menghapus file (menggunakan unlink())
  • jika Anda mengubah opsi, pastikan kode berisi pernyataan untuk mengembalikannya ke yang asli. (mis. op <- par(mfrow=c(1,2)) ...some code... par(op))
  • uji jalankan kode Anda dalam sesi R baru yang kosong untuk memastikan kode tersebut dapat dijalankan. Orang-orang seharusnya hanya bisa menyalin-tempel data dan kode Anda di konsol dan mendapatkan persis sama seperti yang Anda miliki.

Berikan informasi tambahan

Dalam kebanyakan kasus, hanya versi R dan sistem operasi yang cukup. Ketika konflik muncul dengan paket, memberikan hasil sessionInfo()benar-benar dapat membantu. Ketika berbicara tentang koneksi ke aplikasi lain (baik itu melalui ODBC atau apa pun), orang juga harus memberikan nomor versi untuk itu, dan jika mungkin juga informasi yang diperlukan pada pengaturan.

Jika Anda menjalankan R in R Studio menggunakan rstudioapi::versionInfo()dapat membantu untuk melaporkan versi RStudio Anda.

Jika Anda memiliki masalah dengan paket tertentu, Anda mungkin ingin memberikan versi paket dengan memberikan output packageVersion("name of the package").


1 Catatan: Output dari set.seed()perbedaan antara R> 3.6.0 dan versi sebelumnya. Tentukan versi R mana yang Anda gunakan untuk proses acak, dan jangan kaget jika Anda mendapatkan hasil yang sedikit berbeda saat mengikuti pertanyaan lama. Untuk mendapatkan hasil yang sama dalam kasus-kasus seperti itu, Anda dapat menggunakan RNGversion()-fungsi sebelumnya set.seed()(misalnya :) RNGversion("3.5.2").

Joris Meys
sumber
6
Bagaimana Anda menggunakan dputjika bingkai data sangat besar dan masalah dihasilkan oleh tengah bingkai data? Apakah ada cara yang digunakan dputuntuk mereproduksi bagian tengah data, katakanlah baris 60 hingga 70?
BgnR
27
@ BgnR Anda dapat mengekstraksi bagian dari bingkai data menggunakan indeks, misalnya: tmp <- mydf[50:70,]diikuti oleh dput(mydf). Jika bingkai data benar-benar besar, cobalah mengisolasi masalah dan kirimkan beberapa baris yang menyebabkan masalah.
Joris Meys
4
@ JorisMeys: Apakah ada cara untuk memberi tahu headatau dputmembatasi data ke level N secara rekursif? Saya mencoba untuk membuat contoh yang dapat direproduksi dan data saya adalah daftar bingkai data. Jadi, dput(head(myDataObj))sepertinya tidak cukup, karena menghasilkan file output berukuran 14MB.
Aleksandr Blekh
5
@JorisMeys: Just FYI - memposting pertanyaan di komentar di atas sebagai pertanyaan terpisah: stackoverflow.com/questions/25127026/… .
Aleksandr Blekh
4
@Konrad Hal terbaik yang dapat Anda lakukan, adalah menautkan ke file dan memberikan perintah minimal untuk membaca file itu. Itu tidak akan terlalu merepotkan daripada menyalin-menempelkan output dari dput () :)
Joris Meys
590

(Ini saran saya dari Cara menulis contoh yang bisa direproduksi . Saya sudah mencoba membuatnya singkat tapi manis)

Cara menulis contoh yang dapat direproduksi.

Anda kemungkinan besar akan mendapatkan bantuan yang baik dengan masalah R Anda jika Anda memberikan contoh yang dapat direproduksi. Contoh yang direproduksi memungkinkan orang lain untuk menciptakan kembali masalah Anda hanya dengan menyalin dan menempelkan kode R.

Ada empat hal yang perlu Anda sertakan untuk membuat contoh Anda dapat direproduksi: paket yang diperlukan, data, kode, dan deskripsi lingkungan R Anda.

  • Paket harus dimuat di bagian atas skrip, sehingga mudah untuk melihat mana yang dibutuhkan contoh.

  • Cara termudah untuk memasukkan data dalam email atau pertanyaan Stack Overflow adalah dengan menggunakan dput()untuk menghasilkan kode R untuk membuatnya kembali. Misalnya, untuk membuat ulang mtcarsdataset dalam R, saya akan melakukan langkah-langkah berikut:

    1. Jalankan dput(mtcars)di R
    2. Salin hasilnya
    3. Dalam skrip yang dapat saya buat, ketik mtcars <-lalu tempel.
  • Luangkan sedikit waktu untuk memastikan bahwa kode Anda mudah dibaca orang lain:

    • pastikan Anda telah menggunakan spasi dan nama variabel Anda ringkas, tetapi informatif

    • gunakan komentar untuk menunjukkan di mana letak masalah Anda

    • lakukan yang terbaik untuk menghapus semua yang tidak berhubungan dengan masalah.
      Semakin pendek kode Anda, semakin mudah dipahami.

  • Sertakan output sessionInfo()dalam komentar dalam kode Anda. Ini merangkum lingkungan R Anda dan membuatnya mudah untuk memeriksa apakah Anda menggunakan paket yang kedaluwarsa.

Anda dapat memeriksa apakah Anda benar-benar membuat contoh yang dapat direproduksi dengan memulai sesi R baru dan menempelkan skrip Anda di.

Sebelum memasukkan semua kode Anda dalam email, pertimbangkan untuk meletakkannya di Gist github . Ini akan memberi kode Anda sorotan sintaks yang bagus, dan Anda tidak perlu khawatir tentang apa pun yang rusak oleh sistem email.

hadley
sumber
24
reprexin tidyverseadalah paket yang bagus untuk menghasilkan minimal, contoh yang dapat direproduksi: github.com/tidyverse/reprex
mt1022
19
Saya secara rutin menerima email dengan kode di dalamnya. Saya bahkan menerima email dengan dokumen kata terlampir yang berisi kode. Kadang-kadang saya bahkan mendapatkan email dengan dokumen kata terlampir yang berisi SCREENSHOTS kode.
Hadley
304

Secara pribadi, saya lebih suka liners "satu". Sesuatu di sepanjang garis:

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)

Struktur data harus meniru gagasan masalah penulis dan bukan struktur kata demi kata yang tepat. Saya sangat menghargainya ketika variabel tidak menimpa variabel saya sendiri atau tidak, fungsi (seperti df).

Atau, seseorang dapat memotong beberapa sudut dan menunjuk ke set data yang sudah ada sebelumnya, seperti:

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

Jangan lupa menyebutkan paket khusus yang mungkin Anda gunakan.

Jika Anda mencoba mendemonstrasikan sesuatu pada objek yang lebih besar, Anda dapat mencoba

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

Jika Anda bekerja dengan data spasial melalui rasterpaket, Anda dapat menghasilkan beberapa data acak. Banyak contoh dapat ditemukan dalam sketsa paket, tetapi ini adalah nugget kecil.

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)

Jika Anda membutuhkan beberapa objek spasial seperti yang diterapkan sp, Anda bisa mendapatkan beberapa set data melalui file eksternal (seperti ESRI shapefile) dalam paket "spasial" (lihat tampilan Spasial di Tampilan Tugas).

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
sumber
1
IMHO, saat menggunakan sampleatau runiflebih bijaksana set.seed. Setidaknya, ini saran yang saya terima ketika membuat contoh menyampaikan sampel atau pembuatan angka acak.
Konrad
1
@ Konrad saya setuju, tetapi ini mungkin tergantung. Jika Anda hanya mencoba menghasilkan beberapa angka, sebuah seed mungkin tidak diperlukan, tetapi jika Anda mencoba memahami sesuatu yang spesifik di mana angka tetap diperlukan, seed akan menjadi keharusan.
Roman Luštrik
1
Itu selalu lebih baik dengan imo seed, membuatnya lebih mudah untuk membandingkan solusi sendiri dengan output yang diharapkan, untuk membandingkan solusi antara mereka sendiri, dan dengan cara ini pengguna yang tidak tahu (dan tidak perlu tahu) fungsi suka runifatau sampletidak bingung bahwa mereka tidak bisa mendapatkan data yang sama.
Moody_Mudskipper
2
@ Mikey apakah Anda sudah melihat paket usmap ?
Roman Luštrik
2
@mikey paket tigris mengunduh shapefile dari Biro Sensus dalam berbagai format
camille
277

Terinspirasi oleh posting ini, saya sekarang menggunakan fungsi praktis
reproduce(<mydata>)ketika saya perlu memposting ke StackOverflow.


INSTRUKSI CEPAT

Jika myDatanama objek Anda untuk direproduksi, jalankan berikut ini di R:

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

reproduce(myData)

Detail:

Fungsi ini adalah pembungkus cerdas untuk dputdan melakukan hal berikut:

  • secara otomatis sampel kumpulan data besar (berdasarkan ukuran dan kelas. Ukuran sampel dapat disesuaikan)
  • menciptakan dputoutput
  • memungkinkan Anda menentukan kolom mana yang akan diekspor
  • ditambahkan ke depannya objName <- ...sehingga dapat dengan mudah menyalin + menempel, tetapi ...
  • Jika bekerja pada mac, output disalin secara otomatis ke clipboard, sehingga Anda bisa menjalankannya dan menempelkannya ke pertanyaan Anda.

Sumber tersedia di sini:


Contoh:

# 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 sekitar 100 x 102. Saya ingin mencicipi 10 baris, dan beberapa kolom tertentu

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

Memberikan hasil sebagai berikut:

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

Perhatikan juga bahwa keseluruhan output dalam satu baris yang bagus, panjang, bukan paragraf tinggi dari garis yang dicacah. Ini membuatnya lebih mudah untuk membaca pada posting pertanyaan SO dan juga lebih mudah untuk menyalin + menempel.


Pembaruan Oktober 2013:

Anda sekarang dapat menentukan berapa banyak baris output teks akan mengambil (yaitu, apa yang akan Anda tempelkan ke StackOverflow). Gunakan lines.out=nargumen untuk ini. Contoh:

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

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

Ini panduan yang bagus .

Poin yang paling penting adalah: Pastikan Anda membuat sepotong kecil kode yang bisa kita jalankan untuk melihat apa masalahnya . Fungsi yang berguna untuk ini adalah dput(), tetapi jika Anda memiliki data yang sangat besar, Anda mungkin ingin membuat dataset sampel kecil atau hanya menggunakan 10 baris pertama atau lebih.

EDIT:

Pastikan juga Anda mengidentifikasi di mana masalahnya adalah diri Anda sendiri. Contohnya tidak boleh seluruh script R dengan "On line 200 ada kesalahan". Jika Anda menggunakan alat debugging di R (I love browser()) dan Google Anda harus benar-benar dapat mengidentifikasi di mana masalahnya dan mereproduksi contoh sepele di mana hal yang sama salah.

Sacha Epskamp
sumber
165

Milis R-help memiliki panduan pengiriman yang mencakup pertanyaan dan jawaban pertanyaan, termasuk contoh menghasilkan data:

Contoh: Terkadang membantu memberikan contoh kecil bahwa seseorang benar-benar dapat berlari. Sebagai contoh:

Jika saya memiliki matriks x sebagai berikut:

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

bagaimana saya bisa mengubahnya menjadi kerangka data dengan 8 baris, dan tiga kolom bernama 'baris', 'col', dan 'nilai', yang memiliki nama dimensi sebagai nilai 'baris' dan 'col', seperti ini:

  > x.df
     row col value
  1    A   x      1

...
(jawabannya:

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

)

Kata kecil sangat penting. Anda harus membidik contoh minimal yang dapat direproduksi, yang berarti bahwa data dan kode harus sesederhana mungkin untuk menjelaskan masalahnya.

EDIT: Pretty code lebih mudah dibaca daripada kode jelek. Gunakan panduan gaya .

Richie Cotton
sumber
164

Karena R.2.14 (saya kira) Anda dapat memberi makan representasi teks data Anda langsung ke 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
sumber
3
@ sebastian-c bagaimana itu baik untuk membuat contoh yang dapat direproduksi ?? :)
TMS
@ RTM Berpikir serius, jika penanya telah menyediakan data dan masalahnya kecil (tetapi mungkin memiliki beberapa solusi), maka mungkin lebih cepat dan Anda masih dapat mengikuti semua langkah.
sebastian-c
146

Kadang-kadang masalah sebenarnya tidak dapat direproduksi dengan sepotong data yang lebih kecil, tidak peduli seberapa keras Anda mencoba, dan tidak terjadi dengan data sintetis (meskipun itu berguna untuk menunjukkan bagaimana Anda menghasilkan set data sintetis yang tidak mereproduksi masalah, karena itu mengesampingkan beberapa hipotesis).

  • Memposting data ke web di suatu tempat dan menyediakan URL mungkin diperlukan.
  • Jika data tidak dapat dirilis ke publik tetapi dapat dibagikan sama sekali, maka Anda mungkin dapat menawarkan untuk mengirimkannya melalui email kepada pihak yang berkepentingan (meskipun ini akan mengurangi jumlah orang yang akan repot bekerja) di atasnya).
  • Saya belum benar-benar melihat ini dilakukan, karena orang yang tidak dapat merilis data mereka sensitif tentang merilisnya dalam bentuk apa pun, tetapi tampaknya masuk akal bahwa dalam beberapa kasus seseorang masih dapat memposting data jika cukup dianonimkan / diacak / rusak sedikit dalam beberapa cara.

Jika Anda tidak dapat melakukan keduanya, maka Anda mungkin perlu menyewa konsultan untuk menyelesaikan masalah Anda ...

sunting : Dua pertanyaan SO yang berguna untuk penganoniman / pengacakan:

Ben Bolker
sumber
1
Untuk menghasilkan set data sintetis, jawaban atas pertanyaan ini memberikan contoh yang bermanfaat, termasuk aplikasi fitdistrdan fitdistrplus.
Iterator
137

Jawaban sejauh ini jelas bagus untuk bagian reproduktifitas. Ini hanya untuk mengklarifikasi bahwa contoh yang direproduksi tidak dapat dan tidak seharusnya menjadi komponen tunggal dari sebuah pertanyaan. Jangan lupa untuk menjelaskan apa yang Anda inginkan dan kontur masalah Anda, bukan hanya bagaimana Anda berusaha untuk sampai ke sana sejauh ini. Kode tidak cukup; kamu perlu kata-kata juga.

Berikut adalah contoh yang dapat direproduksi dari apa yang harus dihindari (diambil dari contoh nyata, nama diubah untuk melindungi yang tidak bersalah):


Berikut ini adalah contoh data dan bagian dari fungsi yang saya bermasalah.

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

Bagaimana saya bisa mencapai ini?


Ari B. Friedman
sumber
124

Saya memiliki cara yang sangat mudah dan efisien untuk membuat contoh R yang belum disebutkan di atas. Anda dapat menentukan struktur Anda terlebih dahulu. Sebagai contoh,

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

>fix(mydata)

Ketika Anda menjalankan perintah 'fix', Anda akan mendapatkan kotak pop-up ini

Kemudian Anda dapat memasukkan data Anda secara manual. Ini efisien untuk contoh yang lebih kecil daripada yang besar.

jasmine_007
sumber
18
... laludput(mydata)
GSee
Apa frontend Anda? Akan menyenangkan memiliki jawaban yang lengkap. Dll membuat data yang dapat Anda putar secara langsung for (d in data) {...}.
Léo Léopold Hertz 준영
119

Untuk membuat dputdata Anda dengan cepat, Anda cukup menyalin (sepotong) data ke clipboard Anda dan menjalankan yang berikut di R:

untuk data di Excel:

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

untuk data dalam file txt:

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

Anda dapat mengubah sepyang terakhir jika perlu. Ini hanya akan berfungsi jika data Anda ada di clipboard tentunya.

JT85
sumber
116

Pedoman:


Tujuan utama Anda dalam menyusun pertanyaan Anda adalah membuatnya semudah mungkin bagi pembaca untuk memahami dan mereproduksi masalah Anda pada sistem mereka. Untuk melakukannya:

  1. Berikan data input
  2. Berikan hasil yang diharapkan
  3. Jelaskan masalah Anda dengan singkat
    • jika Anda memiliki lebih dari 20 baris teks + kode Anda mungkin dapat kembali dan menyederhanakan
    • sederhanakan kode Anda sebanyak mungkin sambil menjaga masalah / kesalahan

Ini memang membutuhkan beberapa pekerjaan tetapi sepertinya pertukaran yang adil karena Anda meminta orang lain melakukan pekerjaan untuk Anda.

Memberikan data:


Perangkat Data Internal

Opsi terbaik sejauh ini adalah mengandalkan set data bawaan. Ini membuatnya sangat mudah bagi orang lain untuk mengatasi masalah Anda. Ketik data()pada prompt R untuk melihat data apa yang tersedia untuk Anda. Beberapa contoh klasik:

  • iris
  • mtcars
  • ggplot2::diamonds (paket eksternal, tetapi hampir semua orang memilikinya)

Lihat SO QA ini untuk cara menemukan set data yang cocok untuk masalah Anda.

Jika Anda dapat menguraikan kembali masalah Anda untuk menggunakan dataset bawaan, Anda akan lebih mungkin mendapatkan jawaban yang baik (dan upvotes).

Data yang Dihasilkan Sendiri

Jika masalah Anda sangat spesifik untuk tipe data yang tidak terwakili dalam set data yang ada, maka berikan kode R yang menghasilkan dataset sekecil mungkin yang dimanifestasikan oleh masalah Anda. Sebagai contoh

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

Sekarang seseorang yang mencoba menjawab pertanyaan saya dapat menyalin / menempelkan dua baris itu dan segera mulai mengerjakan masalahnya.

dput

Sebagai upaya terakhir , Anda dapat menggunakan dputuntuk mengubah objek data ke kode R (misalnya dput(myData)). Saya katakan sebagai "upaya terakhir" karena hasil dari dputseringkali cukup sulit, mengganggu untuk disalin, dan mengaburkan sisa pertanyaan Anda.

Memberikan Output yang Diharapkan:


Seseorang pernah berkata:

Gambar output yang diharapkan bernilai 1000 kata

- orang yang sangat bijak

Jika Anda dapat menambahkan sesuatu seperti "Saya berharap mendapatkan hasil ini":

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

untuk pertanyaan Anda, orang-orang jauh lebih mungkin untuk dengan cepat memahami apa yang Anda coba lakukan. Jika hasil yang Anda harapkan besar dan sulit, maka Anda mungkin belum cukup memikirkan cara menyederhanakan masalah Anda (lihat selanjutnya).

Jelaskan Masalah Anda Secara Singkat


Hal utama yang harus dilakukan adalah menyederhanakan masalah Anda sebanyak mungkin sebelum Anda mengajukan pertanyaan. Membingkai ulang masalah agar berfungsi dengan dataset bawaan akan banyak membantu dalam hal ini. Anda juga akan sering menemukan bahwa hanya dengan melalui proses penyederhanaan Anda akan menjawab masalah Anda sendiri.

Berikut beberapa contoh pertanyaan bagus:

Dalam kedua kasus, masalah pengguna hampir pasti tidak dengan contoh sederhana yang mereka berikan. Sebaliknya mereka mengabstraksi sifat masalah mereka dan menerapkannya pada set data sederhana untuk mengajukan pertanyaan mereka.

Mengapa Ada Lagi Jawaban untuk Pertanyaan Ini?


Jawaban ini berfokus pada apa yang menurut saya merupakan praktik terbaik: gunakan kumpulan data bawaan dan berikan apa yang Anda harapkan sebagai hasil dalam bentuk minimal. Jawaban yang paling menonjol fokus pada aspek lain. Saya tidak mengharapkan jawaban ini naik ke keunggulan apa pun; ini di sini semata-mata agar saya dapat menautkannya dalam komentar untuk pertanyaan pemula.

BrodieG
sumber
113

Kode yang dapat direproduksi adalah kunci untuk mendapatkan bantuan. Namun, ada banyak pengguna yang mungkin skeptis menyisipkan bahkan sepotong data mereka. Misalnya, mereka dapat bekerja dengan data sensitif atau data asli yang dikumpulkan untuk digunakan dalam makalah penelitian. Untuk alasan apa pun, saya pikir akan menyenangkan memiliki fungsi praktis untuk "mendeformasi" data saya sebelum menempelkannya secara publik. The anonymizefungsi dari paket SciencesPoini sangat konyol, tapi bagi saya itu bekerja dengan baik dengan dputfungsi.

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

Lalu saya anonimkan:

> 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

Seseorang mungkin juga ingin mengambil sampel beberapa variabel daripada seluruh data sebelum menerapkan perintah anonimisasi dan 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
sumber
102

Seringkali Anda memerlukan beberapa data sebagai contoh, namun Anda tidak ingin memposting data yang tepat. Untuk menggunakan beberapa data.frame yang ada di perpustakaan yang didirikan, gunakan perintah data untuk mengimpornya.

misalnya,

data(mtcars)

dan kemudian lakukan masalahnya

names(mtcars)
your problem demostrated on the mtcars data set
userJT
sumber
13
Banyak set data bawaan (seperti kumpulan data mtcarsdan populer iris) tidak benar-benar membutuhkan datapanggilan untuk digunakan.
Gregor Thomas
92

Jika Anda memiliki dataset besar yang tidak dapat dengan mudah dimasukkan ke skrip menggunakan dput(), posting data Anda ke pastebin dan muat menggunakan read.table:

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

Terinspirasi oleh @Henrik .

TMS
sumber
90

Saya sedang mengembangkan paket wakefield untuk mengatasi kebutuhan ini untuk dengan cepat berbagi data yang dapat direproduksi, kadang-kadang dputberfungsi dengan baik untuk set data yang lebih kecil tetapi banyak dari masalah yang kita tangani jauh lebih besar, berbagi set data yang besar melalui dputtidak praktis.

Tentang:

wakefield memungkinkan pengguna untuk membagikan kode minimal untuk mereproduksi data. Pengguna menyeteln(jumlah baris) dan menentukan sejumlah fungsi variabel preset (saat ini ada 70) yang meniru data real if (hal-hal seperti jenis kelamin, usia, pendapatan, dll.)

Instalasi:

Saat ini (2015-06-11), wakefield adalah paket GitHub tetapi akan pergi ke CRAN setelah unit test ditulis. Untuk menginstal dengan cepat, gunakan:

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

Contoh:

Berikut ini sebuah contoh:

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

Ini menghasilkan:

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

Jika Anda memiliki satu atau lebih factorvariabel dalam data yang ingin Anda buat direproduksi dput(head(mydata)), pertimbangkan droplevelsuntuk menambahkannya , sehingga tingkat faktor yang tidak ada dalam kumpulan data yang diperkecil tidak termasuk dalam dputoutput Anda , untuk buat contoh minimal :

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

Saya ingin tahu apakah tautan http://old.r-fiddle.org/ bisa menjadi cara berbagi masalah yang sangat rapi. Ia menerima ID unik seperti dan orang bahkan bisa berpikir tentang menanamkannya dalam SO.

CMichael
sumber
47

Tolong jangan tempel output konsol Anda seperti ini:

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

Kami tidak dapat menyalin-menempelkannya secara langsung.

Untuk membuat pertanyaan dan jawaban yang dapat direproduksi dengan benar, coba hapus +& >sebelum mempostingnya dan berikan #output dan komentar seperti ini:

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

Satu hal lagi, jika Anda telah menggunakan fungsi apa pun dari paket tertentu, sebutkan perpustakaan itu.

user2100721
sumber
2
apakah Anda menghapus >dan menambahkan #secara manual atau apakah ada cara otomatis untuk melakukannya?
BCArg
3
@ BCArg saya hapus >secara manual. Tapi, sebagai tambahan #, saya menggunakan Ctrl+Shift+Cshortcut di RStudioeditor.
user2100721
33

Anda dapat melakukan ini menggunakan reprex .

Seperti yang dicatat oleh mt1022 , "... paket yang bagus untuk menghasilkan contoh yang minimal dan dapat direproduksi adalah " reprex " dari tidyverse ".

Menurut Tidyverse :

Tujuan dari "reprex" adalah mengemas kode bermasalah Anda sedemikian rupa sehingga orang lain dapat menjalankannya dan merasakan rasa sakit Anda.

Contoh diberikan di situs web rapi .

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

Saya pikir ini adalah cara paling sederhana untuk membuat contoh yang dapat direproduksi.

andrii
sumber
33

Terlepas dari semua jawaban di atas yang saya temukan sangat menarik, kadang-kadang bisa sangat mudah seperti yang dibahas di sini: - CARA MEMBUAT CONTOH REPRODUKSI MINIMAL UNTUK MENDAPATKAN BANTUAN DENGAN R

Ada banyak cara untuk membuat vektor acak. Buat vektor angka 100 dengan nilai acak dalam R dibulatkan menjadi 2 desimal atau matriks acak dalam R

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

Perhatikan bahwa kadang-kadang sangat sulit untuk membagikan data yang diberikan karena berbagai alasan seperti dimensi dll. Namun, semua jawaban di atas sangat bagus dan sangat penting untuk dipikirkan dan digunakan ketika seseorang ingin membuat contoh data yang dapat direproduksi. Tetapi perhatikan bahwa untuk membuat data sebagai representatif seperti aslinya (jika OP tidak dapat membagikan data asli), ada baiknya menambahkan beberapa informasi dengan contoh data sebagai (jika kita memanggil data mydf1)

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

Selain itu, orang harus mengetahui tipe, panjang, dan atribut dari suatu data yang dapat berupa struktur 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))
pengguna5947301
sumber
28

Berikut beberapa saran saya:

  • Cobalah untuk menggunakan dataset R default
  • Jika Anda memiliki dataset sendiri, sertakan dengan dput, sehingga yang lain dapat membantu Anda dengan lebih mudah
  • Jangan gunakan install.package()kecuali itu benar-benar diperlukan, orang akan mengerti jika Anda hanya menggunakan requireataulibrary
  • Cobalah untuk ringkas,

    • Memiliki beberapa dataset
    • Cobalah untuk menggambarkan output yang Anda butuhkan sesederhana mungkin
    • Lakukan sendiri sebelum Anda mengajukan pertanyaan
  • Sangat mudah untuk mengunggah gambar, jadi unggah plot jika Anda punya
  • Sertakan juga kesalahan yang mungkin Anda miliki

Semua ini adalah bagian dari contoh yang dapat direproduksi.

TheRimalaya
sumber
1
Anda belum menambahkan zat apa pun di sini. dput()telah disebutkan sebelumnya, dan banyak dari ini hanya mengulangi pedoman standar SO.
Rich Scriven
1
Saya mengalami masalah dengan install.packagefungsi termasuk dalam contoh yang tidak benar-benar diperlukan (menurut pendapat saya). Selanjutnya, menggunakan dataset R default akan membuat yang direproduksi lebih mudah. Pedoman SO belum membicarakan apa pun tentang topik-topik ini secara khusus. Selanjutnya, itu dimaksudkan untuk memberikan pendapat saya dan ini adalah yang paling saya temui.
TheRimalaya
18

Sebaiknya gunakan fungsi dari testthatpaket untuk menunjukkan apa yang Anda harapkan terjadi. Dengan demikian, orang lain dapat mengubah kode Anda hingga berjalan tanpa kesalahan. Ini meringankan beban mereka yang ingin membantu Anda, karena itu berarti mereka tidak perlu men-decode deskripsi teks Anda. Sebagai contoh

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

lebih jelas daripada "Saya pikir x akan keluar menjadi 1,23 untuk y sama dengan atau melebihi 10, dan 3,21 sebaliknya, tapi saya tidak mendapat hasil". Bahkan dalam contoh konyol ini, saya pikir kodenya lebih jelas daripada kata-kata. Menggunakan testthatmemungkinkan penolong Anda fokus pada kode, yang menghemat waktu, dan menyediakan cara bagi mereka untuk mengetahui bahwa mereka telah memecahkan masalah Anda, sebelum mereka mempostingnya

lembab
sumber