Pertanyaan Bagaimana cara membuat contoh yang bagus untuk direproduksi?


Ketika mendiskusikan kinerja dengan rekan kerja, mengajar, mengirim laporan bug atau mencari panduan di milis dan di sini di SO, a contoh yang dapat direproduksi sering ditanyakan dan selalu membantu.

Apa kiat Anda untuk membuat contoh yang bagus? Bagaimana Anda menempelkan struktur data dari  dalam format teks? Informasi apa lagi yang harus Anda sertakan?

Adakah trik lain selain menggunakan dput(), dump() atau structure()? Kapan Anda harus memasukkannya library() atau require() pernyataan? Kata-kata yang dicadangkan harus dihindari, selain c, df, data, dll?

Bagaimana cara seseorang menjadi hebat  contoh yang dapat direproduksi?


2373


asal


Jawaban:


Contoh yang dapat direproduksi minimal terdiri dari item berikut:

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

Melihat contoh dalam file bantuan fungsi yang digunakan sering membantu. Secara umum, semua kode yang diberikan di sana memenuhi persyaratan dari contoh yang dapat direproduksi minimal: data disediakan, kode minimal disediakan, dan semuanya dapat dijalankan.

Menghasilkan dataset minimal

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

Membuat vektor itu mudah. Kadang-kadang perlu menambahkan beberapa keacakan untuk itu, dan ada sejumlah fungsi untuk membuat itu. sample() dapat mengacak vektor, atau memberikan vektor acak hanya dengan beberapa nilai. letters adalah 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 matrik, seseorang bisa menggunakannya matrix(), misalnya:

matrix(1:10, ncol = 2)

Pembuatan frame data dapat dilakukan menggunakan data.frame(). Satu 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 khusus dapat diperlukan. Untuk ini, orang dapat menggunakan salah satu yang disediakan as.someType fungsi: as.factor, as.Date, as.xts, ... Ini dalam kombinasi dengan vektor dan / atau trik bingkai data.

Salin data Anda

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

> dput(head(iris,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 = 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, maka dput output bisa berat karena akan tetap daftar semua kemungkinan tingkat faktor bahkan jika mereka tidak hadir di subset dari data Anda. Untuk mengatasi masalah ini, Anda dapat menggunakan droplevels() fungsi. Perhatikan di bawah ini bagaimana spesies adalah faktor dengan hanya satu level:

> dput(droplevels(head(iris, 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")

Satu peringatan lain untuk dput adalah bahwa itu tidak akan berfungsi untuk mengetik data.table benda atau untuk dikelompokkan tbl_df (kelas grouped_df) dari dplyr. Dalam kasus ini, Anda dapat mengonversi kembali ke bingkai data biasa sebelum dibagikan, dput(as.data.frame(my_data)).

Skenario terburuk, Anda dapat memberikan representasi teks yang dapat dibaca dalam menggunakan text parameter dari 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)

Menghasilkan kode minimal

Ini seharusnya menjadi bagian yang mudah tetapi sering tidak. Apa yang seharusnya tidak Anda lakukan, adalah:

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

Yang harus Anda lakukan adalah:

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

Berikan informasi tambahan

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

Jika Anda menjalankan R dalam 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").


1450



(Ini saran saya dari Cara menulis contoh yang dapat direproduksi . Saya sudah mencoba membuatnya pendek 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 dapat direproduksi memungkinkan orang lain untuk membuat ulang masalah Anda dengan hanya 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.

  • Paketharus dimuat di bagian atas skrip, jadi mudah saja lihat mana yang perlu contoh.

  • Cara termudah untuk disertakan data dalam email atau pertanyaan Stack Overflow adalah untuk digunakan dput() untuk menghasilkan kode R untuk membuatnya kembali. Misalnya, untuk membuat ulang mtcars kumpulan data dalam R, Saya akan melakukan langkah-langkah berikut:

    1. Menjalankan dput(mtcars) di R
    2. Salin hasilnya
    3. Dalam naskah saya yang dapat direproduksi, ketik mtcars <- lalu tempelkan.
  • Luangkan sedikit waktu untuk memastikan bahwa Anda kode mudah bagi orang lain Baca baca:

    • 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 terkait dengan masalah.
      Semakin pendek kode Anda, semakin mudah untuk dipahami.

  • Termasuk output dari sessionInfo() dalam komentar di kode Anda. Ini merangkum Anda R lingkungan Hidup dan membuatnya mudah untuk memeriksa apakah Anda menggunakan yang sudah ketinggalan zaman paket.

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

Sebelum memasukkan semua kode Anda ke dalam email, pertimbangkan untuk memakainya Gist github . Ini akan memberi kode yang bagus untuk penyorotan sintaks Anda, dan Anda tidak perlu khawatir tentang apa pun yang dirusak oleh sistem email.


514



Secara pribadi, saya lebih memilih "satu" liners. 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 ide masalah penulis dan bukan struktur kata demi kata yang tepat. Saya sangat menghargai ketika variabel tidak menimpa variabel saya sendiri atau dilarang, fungsi (seperti df).

Atau, orang bisa memotong beberapa sudut dan menunjuk ke kumpulan data yang sudah ada sebelumnya, sesuatu seperti:

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

Jangan lupa untuk menyebutkan paket-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 raster paket, Anda dapat menghasilkan beberapa data acak. Banyak contoh yang bisa ditemukan di paket vignette, tapi inilah 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 di sp, Anda bisa mendapatkan beberapa set data melalui file eksternal (seperti shapefile ESRI) 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")

258



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


INSTRUKSI CEPAT

Jika myData adalah nama objek Anda untuk mereproduksi, jalankan yang berikut 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 dput dan lakukan hal berikut:

  • otomatis sampel kumpulan data besar (berdasarkan ukuran dan kelas. Ukuran sampel dapat disesuaikan)
  • menciptakan a dput keluaran
  • memungkinkan Anda untuk menentukan yang kolom untuk diekspor
  • menambahkan ke depannya objName <- ... sehingga dapat dengan mudah disalin + ditempel, tapi ...
  • Jika bekerja pada mac, output secara otomatis disalin ke clipboard, sehingga Anda dapat menjalankannya dan menempelkannya ke pertanyaan Anda.

Sumbernya 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 adalah sekitar 100 x 102. Saya ingin mengambil sampel 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 panjang yang bagus, bukan paragraf tinggi dari garis yang dicincang. Ini membuatnya lebih mudah untuk membaca pada posting pertanyaan SO dan juga lebih mudah untuk menyalin + tempel.


Perbarui Oktober 2013:

Anda sekarang dapat menentukan berapa banyak baris output teks akan mengambil (yaitu, apa yang akan Anda tempelkan ke StackOverflow). Menggunakan lines.out=n argumen 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==

241



Berikut ini panduan yang bagus:

http://www.r-bloggers.com/three-tips-for-posting-good-questions-to-r-help-and-stack-overflow/

Tetapi yang paling penting adalah: Pastikan Anda membuat potongan kecil kode yang dapat 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:

Juga pastikan bahwa Anda mengidentifikasi di mana masalahnya sendiri. Contohnya tidak boleh seluruh skrip R dengan "On line 200 ada kesalahan". Jika Anda menggunakan alat debugging di R (Saya suka browser()) dan google Anda harus dapat benar-benar mengidentifikasi di mana masalahnya dan mereproduksi contoh sepele di mana hal yang sama terjadi salah.


168



Milis R-help memiliki panduan posting yang mencakup pertanyaan bertanya dan menjawab, termasuk contoh menghasilkan data:

Contoh: Terkadang membantu   berikan contoh kecil bahwa seseorang   sebenarnya bisa berjalan. 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 dataframe   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

...
  (Yang jawabannya mungkin:

  > 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 mengincar a minimal contoh yang dapat direproduksi, yang berarti bahwa data dan kode harus sesederhana mungkin untuk menjelaskan masalah.

EDIT: Kode cantik lebih mudah dibaca daripada kode jelek. Gunakan panduan gaya.


142



Karena R.2.14 (Saya kira) Anda dapat memberi makan representasi teks data Anda langsung ke read.table:

df <- read.table(header=T, 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
") 

136



Kadang-kadang masalah benar-benar tidak dapat direproduksi dengan data yang lebih kecil, tidak peduli seberapa keras Anda mencoba, dan tidak terjadi dengan data sintetis (meskipun ini berguna untuk menunjukkan bagaimana Anda menghasilkan kumpulan data sintetik yang melakukan tidak mereproduksi masalah, karena mengesampingkan beberapa hipotesis).

  • Posting data ke web di suatu tempat dan menyediakan URL mungkin diperlukan.
  • Jika data tidak dapat dirilis ke publik pada umumnya tetapi bisa dibagikan sama sekali, maka Anda mungkin dapat menawarkan untuk mengirim e-mail ke pihak yang berkepentingan (meskipun ini akan mengurangi jumlah orang yang akan repot-repot untuk bekerja di atasnya).
  • Saya belum benar-benar melihat ini dilakukan, karena orang-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 itu cukup dianonimkan / diacak / rusak sedikit dalam beberapa cara.

Jika Anda tidak dapat melakukan salah satu dari ini maka Anda mungkin perlu menyewa konsultan untuk memecahkan masalah Anda ...

sunting: Dua pertanyaan SO yang berguna untuk anonymization / scrambling:


126