Как сделать отличный воспроизводимый пример R

May 11 2011

При обсуждении производительности с коллегами, обучении, отправке отчета об ошибке или поиске руководства в списках рассылки и здесь, в Stack Overflow, часто спрашивают воспроизводимый пример, который всегда оказывается полезным.

Каковы ваши советы по созданию отличного примера? Как вставить структуры данных из r в текстовый формат? Какую еще информацию вы должны включить?

Есть ли другие уловки помимо использования dput(), dump()или structure()? Когда следует включать library()или require()утверждения? Какие зарезервированные слова следует один избежать, в дополнение к c, df, dataи т.д.?

Как один сделать большой г воспроизводимый пример?

Ответы

1756 JorisMeys May 11 2011 at 18:40

Минимальный воспроизводимый пример состоит из следующих элементов:

  • минимальный набор данных, необходимый для демонстрации проблемы
  • минимальный исполняемый код, необходимый для воспроизведения ошибки, который может быть запущен для данного набора данных
  • необходимую информацию об используемых пакетах, версии 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))
  • test запустите свой код в новом пустом сеансе R, чтобы убедиться, что код запускается. Люди должны иметь возможность просто скопировать и вставить ваши данные и код в консоль и получить то же самое, что и вы.

Дайте дополнительную информацию

В большинстве случаев достаточно только версии R и операционной системы. Когда возникают конфликты с пакетами, sessionInfo()действительно может помочь вывод . Говоря о подключениях к другим приложениям (будь то через ODBC или что-то еще), следует также указать номера версий для них и, если возможно, также необходимую информацию по настройке.

Если вы работаете R в R Studio , используя rstudioapi::versionInfo()может быть полезным , чтобы сообщить свою версию RStudio.

Если у вас есть проблема с конкретным пакетом, вы можете указать версию пакета, предоставив вывод packageVersion("name of the package").


1 Примечание . Вывод set.seed()отличается для R> 3.6.0 и предыдущих версий. Укажите, какую версию R вы использовали для случайного процесса, и не удивляйтесь, если вы получите несколько другие результаты, отвечая на старые вопросы. Чтобы получить тот же результат в таких случаях, вы можете использовать RNGversion()-функцию до set.seed()(например :) RNGversion("3.5.2").

595 hadley May 11 2011 at 20:57

(Вот мой совет из статьи Как написать воспроизводимый пример . Я попытался сделать его кратким, но милым)

Как написать воспроизводимый пример.

Скорее всего, вы получите хорошую помощь в решении проблемы с R, если предоставите воспроизводимый пример. Воспроизводимый пример позволяет кому-то другому воссоздать вашу проблему, просто скопировав и вставив код R.

Чтобы сделать ваш пример воспроизводимым, вам нужно включить четыре вещи: необходимые пакеты, данные, код и описание вашей среды R.

  • Пакеты должны загружаться в верхней части скрипта, чтобы было легко увидеть, какие из них нужны в примере.

  • Самый простой способ включить данные в электронное письмо или вопрос о переполнении стека - это использовать dput()для создания кода R для его воссоздания. Например, чтобы воссоздать mtcarsнабор данных в R, я бы выполнил следующие шаги:

    1. Беги dput(mtcars)в R
    2. Скопируйте вывод
    3. В моем воспроизводимом скрипте введите и mtcars <-вставьте.
  • Потратьте немного времени на то, чтобы ваш код было легко читать другим:

    • убедитесь, что вы использовали пробелы и имена переменных были краткими, но информативными

    • используйте комментарии, чтобы указать, в чем заключается ваша проблема

    • постарайтесь удалить все, что не имеет отношения к проблеме.
      Чем короче ваш код, тем легче его понять.

  • Включите вывод sessionInfo()в комментарий в свой код. Это обобщает вашу среду R и позволяет легко проверить, используете ли вы устаревший пакет.

Вы можете проверить, действительно ли вы создали воспроизводимый пример, запустив новый сеанс R и вставив свой скрипт.

Прежде чем помещать весь свой код в электронное письмо, подумайте о том, чтобы разместить его на Gist github . Это придаст вашему коду приятную подсветку синтаксиса, и вам не придется беспокоиться о том, что почтовая система может что-то испортить.

307 RomanLuštrik May 11 2011 at 18:22

Лично я предпочитаю «одинарные» вкладыши. Что-то вроде:

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")
281 RicardoSaporta May 14 2013 at 05:20

Вдохновленный этим постом, теперь я использую удобную функцию,
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, вывод автоматически копируется в буфер обмена, так что вы можете просто запустить его, а затем вставить в свой вопрос.

Источник доступен здесь:

  • Github - pubR / duplicate.R

Пример:

# 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 г .:

Теперь вы можете указать, сколько строк текста будет занимать вывод (т. Е. Что вы будете вставлять в 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==
198 SachaEpskamp May 11 2011 at 18:21

Вот хорошее руководство .

Самый важный момент: просто убедитесь, что вы создали небольшой фрагмент кода, который мы можем запустить, чтобы увидеть, в чем проблема . Для этого полезна функция dput(), но если у вас очень большие данные, вы можете создать небольшой образец набора данных или использовать только первые 10 строк или около того.

РЕДАКТИРОВАТЬ:

Также убедитесь, что вы сами определили, в чем проблема. Примером не должно быть всего сценария R с надписью «В строке 200 есть ошибка». Если вы используете инструменты отладки в R (я люблю browser()) и Google, вы действительно сможете определить, в чем проблема, и воспроизвести тривиальный пример, в котором то же самое идет не так.

167 RichieCotton May 11 2011 at 20:17

В списке рассылки 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', которые имеют имена измерений как значения '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 Paolo Jun 29 2012 at 15:32

Начиная с 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
") 
146 BenBolker Jul 15 2011 at 02:49

Иногда проблема действительно не воспроизводится с меньшим фрагментом данных, как бы вы ни старались, и не возникает с синтетическими данными (хотя полезно показать, как вы создали наборы синтетических данных, которые не воспроизводили проблему, потому что это исключает некоторые гипотезы).

  • Может потребоваться размещение данных в Интернете и предоставление URL-адреса.
  • Если данные не могут быть опубликованы для широкой публики, но могут быть переданы вообще, вы можете предложить отправить их по электронной почте заинтересованным сторонам (хотя это сократит количество людей, которые будут беспокоиться о работе. в теме).
  • Я на самом деле не видел этого, потому что люди, которые не могут выпустить свои данные, чувствительны к выпуску их в любой форме, но может показаться правдоподобным, что в некоторых случаях можно было бы публиковать данные, если бы они были достаточно анонимными / зашифрованными / слегка поврежденными каким-то образом.

Если вы не можете сделать ни одно из этих действий, вам, вероятно, потребуется нанять консультанта для решения вашей проблемы ...

edit : Два полезных вопроса SO для анонимизации / скремблирования:

  • Как создать примерный набор данных из частных данных (заменив имена и уровни переменных неинформативными заполнителями)?
  • Учитывая набор случайных чисел, взятых из непрерывного одномерного распределения, найдите распределение
136 AriB.Friedman Jul 09 2012 at 22:41

Пока что ответы явно хороши в отношении воспроизводимости. Это просто для того, чтобы прояснить, что воспроизводимый пример не может и не должен быть единственным компонентом вопроса. Не забудьте объяснить, как вы хотите, чтобы это выглядело, и контуры вашей проблемы, а не только то, как вы до сих пор пытались ее решить. Кода недостаточно; вам также нужны слова.

Вот воспроизводимый пример того, чего следует избегать (взят из реального примера, имена изменены для защиты невиновных):


Ниже приведены примеры данных и часть функции, с которой у меня возникли проблемы.

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

Как я могу этого добиться?


124 jasmine_007 Feb 20 2014 at 16:11

У меня есть очень простой и эффективный способ сделать пример R, который не упоминался выше. Вы можете сначала определить свою структуру. Например,

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

>fix(mydata)

Затем вы можете ввести свои данные вручную. Это более эффективно для небольших примеров, чем для больших.

119 JT85 Apr 10 2013 at 21:51

Чтобы быстро создать dputчасть своих данных, вы можете просто скопировать (часть) данных в буфер обмена и запустить в R следующее:

для данных в Excel:

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

для данных в txt файле:

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

При необходимости вы можете изменить sepпоследнее. Это будет работать, только если ваши данные, конечно, находятся в буфере обмена.

118 BrodieG Feb 12 2015 at 22:24

Руководящие указания:


Ваша основная цель при составлении вопросов должна заключаться в том, чтобы читателям было как можно проще понять и воспроизвести вашу проблему в своих системах. Для этого:

  1. Предоставьте входные данные
  2. Обеспечьте ожидаемый результат
  3. Кратко объясните свою проблему
    • если у вас более 20 строк текста + код, вы, вероятно, можете вернуться и упростить
    • максимально упростите свой код, сохранив проблему / ошибку

Это требует некоторой работы, но кажется справедливым компромиссом, поскольку вы просите других делать работу за вас.

Предоставление данных:


Встроенные наборы данных

На сегодняшний день лучший вариант - полагаться на встроенные наборы данных. Это упрощает другим работу над вашей проблемой. Введите data()в приглашении R, чтобы узнать, какие данные вам доступны. Некоторые классические примеры:

  • iris
  • mtcars
  • ggplot2::diamonds (внешний пакет, но он есть почти у всех)

Изучите встроенные наборы данных, чтобы найти подходящий для вашей проблемы.

Если вы сможете перефразировать свою проблему и использовать встроенные наборы данных, у вас гораздо больше шансов получить хорошие ответы (и положительные голоса).

Самостоятельно созданные данные

Если ваша проблема очень специфична для типа данных, который не представлен в существующих наборах данных, предоставьте код R, который генерирует минимально возможный набор данных, в котором проявляется ваша проблема. Например

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

Теперь кто-то, кто пытается ответить на мой вопрос, может скопировать / вставить эти две строки и немедленно начать работу над проблемой.

dput

В крайнем случае вы можете использовать dputдля преобразования объекта данных в код R (например dput(myData)). Я говорю «в крайнем случае», потому что вывод dputчасто бывает довольно громоздким, раздражающим для копирования и вставки и скрывает остальную часть вашего вопроса.

Обеспечьте ожидаемый результат:


Кто-то однажды сказал:

Изображение ожидаемого результата стоит 1000 слов

- очень мудрый человек

Если вы можете добавить что-то вроде «Я ожидал получить такой результат»:

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

Отвечая на ваш вопрос, люди с гораздо большей вероятностью поймут, что вы пытаетесь сделать. Если ваш ожидаемый результат большой и громоздкий, то вы, вероятно, недостаточно думали о том, как упростить вашу задачу (см. Далее).

Кратко объясните свою проблему


Главное, что нужно сделать, это максимально упростить вашу проблему, прежде чем вы зададите свой вопрос. В этом отношении очень поможет переформулирование проблемы для работы со встроенными наборами данных. Вы также часто обнаруживаете, что, просто пройдя через процесс упрощения, вы решите свою собственную проблему.

Вот несколько примеров хороших вопросов:

  • со встроенным набором данных
  • с пользовательскими данными

В обоих случаях проблемы пользователя почти наверняка связаны не с теми простыми примерами, которые они предоставляют. Скорее они абстрагировались от природы своей проблемы и применили ее к простому набору данных, чтобы задать свой вопрос.

Почему еще один ответ на этот вопрос?


В этом ответе основное внимание уделяется тому, что я считаю лучшей практикой: использовать встроенные наборы данных и предоставлять то, что вы ожидаете, в минимальной форме. Наиболее известные ответы сосредоточены на других аспектах. Я не ожидаю, что этот ответ станет известен; это здесь исключительно для того, чтобы я мог ссылаться на него в комментариях к вопросам новичков.

113 daniel Nov 27 2014 at 09:02

Воспроизводимый код - ключ к получению помощи. Однако многие пользователи могут скептически относиться к вставке даже части своих данных. Например, они могут работать с конфиденциальными данными или с исходными данными, собранными для использования в исследовательской работе. По какой-то причине я подумал, что было бы неплохо иметь удобную функцию для «деформации» моих данных перед их публичной вставкой. 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 userJT Feb 22 2013 at 22:29

Часто вам нужны данные для примера, однако вы не хотите публиковать свои точные данные. Чтобы использовать существующий data.frame в установленной библиотеке, используйте команду data для его импорта.

например,

data(mtcars)

а затем займитесь проблемой

names(mtcars)
your problem demostrated on the mtcars data set
92 TMS Jan 04 2014 at 02:07

Если у вас большой набор данных, который не может быть легко помещен в скрипт с помощью dput(), опубликуйте свои данные в pastebin и загрузите их, используя read.table:

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

На основе @Henrik .

90 TylerRinker Jun 11 2015 at 20:57

Я разрабатываю пакет wakefield , чтобы удовлетворить эту потребность в быстром обмене воспроизводимыми данными, иногда dputотлично работает для небольших наборов данных, но многие проблемы, с которыми мы сталкиваемся, намного больше, совместное использование такого большого набора данных через посредство dputнепрактично.

О:

wakefield позволяет пользователю делиться минимальным кодом для воспроизведения данных. Пользователь устанавливаетn(количество строк) и определяет любое количество предварительно установленных функций переменных (в настоящее время их 70), которые имитируют реальные данные if (такие как пол, возраст, доход и т. Д.)

Установка:

В настоящее время (11.06.2015) 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
.. ...   ... ...    ...      ... ...    ...   ...
73 docendodiscimus Jan 09 2015 at 22:09

Если у вас есть одна или несколько factorпеременных в ваших данных, которые вы хотите сделать воспроизводимыми dput(head(mydata)), подумайте о добавлении droplevelsк ним, чтобы уровни факторов, которые не присутствуют в минимизированном наборе данных, не включались в ваш dputвывод, чтобы сделайте пример минимальным :

dput(droplevels(head(mydata)))
66 CMichael Jan 09 2015 at 20:11

Интересно, если http://old.r-fiddle.org/ссылка может быть очень изящным способом поделиться проблемой. Он получает уникальный идентификатор вроде и можно даже подумать о встраивании его в SO.

49 user2100721 Jul 22 2016 at 17:01

Пожалуйста, не вставляйте выходные данные консоли следующим образом:

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

Еще одна вещь: если вы использовали какую-либо функцию из определенного пакета, укажите эту библиотеку.

34 andrii Aug 19 2017 at 02:02

Вы можете сделать это с помощью REPEX .

Как заметил mt1022 , «... хороший пакет для создания минимального воспроизводимого примера - это « реплекс » из tidyverse ».

Согласно Tidyverse :

Цель "REPEX" - упаковать ваш проблемный код таким образом, чтобы другие люди могли запустить его и почувствовать вашу боль.

Пример приведен на сайте tidyverse .

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

Я думаю, что это самый простой способ создать воспроизводимый пример.

33 5revs,2users84%user5947301 Apr 20 2016 at 17:50

Помимо всех приведенных выше ответов, которые мне показались очень интересными, иногда это может быть очень просто, поскольку это обсуждается здесь: - КАК СДЕЛАТЬ МИНИМАЛЬНЫЙ ВОСПРОИЗВОДИМЫЙ ПРИМЕР ДЛЯ ПОЛУЧЕНИЯ ПОМОЩИ С R

Есть много способов создать случайный вектор. Создайте вектор из 100 чисел со случайными значениями в R, округленными до 2 десятичных знаков, или случайную матрицу в 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 TheRimalaya Apr 10 2016 at 01:15

Вот некоторые из моих предложений:

  • Попробуйте использовать наборы данных R по умолчанию
  • Если у вас есть собственный набор данных, включите его dput, чтобы другие могли вам помочь.
  • Не используйте, install.package()если это действительно не нужно, люди поймут, если вы просто используете requireилиlibrary
  • Постарайтесь быть краткими,

    • Есть какой-то набор данных
    • Постарайтесь как можно проще описать желаемый результат
    • Сделайте это сами, прежде чем задать вопрос
  • Загрузить изображение легко, поэтому загружайте графики, если у вас есть
  • Также укажите все возможные ошибки.

Все это часть воспроизводимого примера.

18 dank Apr 05 2017 at 04:08

Рекомендуется использовать функции из testthatпакета, чтобы показать, что вы ожидаете. Таким образом, другие люди могут изменять ваш код до тех пор, пока он не будет работать без ошибок. Это облегчает бремя тех, кто хотел бы вам помочь, потому что это означает, что им не нужно декодировать ваше текстовое описание. Например

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

яснее, чем «Я думаю, что x будет 1,23 для y, равного или превышающего 10, и 3,21 в противном случае, но я не получил ни одного результата». Даже в этом глупом примере я думаю, что код яснее слов. Использование testthatпозволяет вашему помощнику сосредоточиться на коде, что экономит время, и дает им возможность узнать, что они решили вашу проблему, прежде чем опубликовать ее.