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

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

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

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

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

Ответ 1

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

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

Важное примечание: вывод set.seed() отличается между R> 3.6.0 и предыдущими версиями. Укажите, какую версию R вы использовали для случайного процесса.

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

Создание минимального набора данных

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

Если у вашего фрейма данных есть фактор с множеством уровней, вывод dput может быть громоздким, поскольку он по-прежнему будет перечислять все возможные уровни факторов, даже если их нет в подмножестве ваших данных. Чтобы решить эту проблему, вы можете использовать droplevels(). Ниже обратите внимание, как вид является фактором только с одним уровнем:

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

Еще одно предостережение для dput заключается в том, что он не будет работать для объектов data.table или для сгруппированных tbl_df (класс grouped_df) из dplyr. В этих случаях вы можете преобразовать обратно в обычный фрейм данных перед совместным использованием dput(as.data.frame(my_data)).

В худшем случае вы можете дать текстовое представление, которое можно прочитать, используя text параметр read.table:

zz <- "Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa"

Data <- read.table(text=zz, header = TRUE)

Создание минимального кода

Это должно быть легкой частью, но часто это не так. Что вы не должны делать, это:

  • добавить все виды преобразований данных. Убедитесь, что предоставленные данные уже в правильном формате (если, конечно, это не проблема)
  • Скопируйте и вставьте целую функцию/кусок кода, который выдает ошибку. Во-первых, попытайтесь определить, какие именно строки приводят к ошибке. Чаще всего вы сами узнаете, в чем проблема.

Что вы должны сделать, это:

  • добавьте, какие пакеты следует использовать, если вы их используете (используя library())
  • если вы открываете соединения или создаете файлы, добавьте некоторый код, чтобы закрыть их или удалить файлы (используя unlink())
  • если вы изменяете параметры, убедитесь, что в коде есть инструкция, чтобы вернуть их обратно к исходным. (например, op <- par(mfrow=c(1,2))...some code... par(op))
  • Запустите ваш код в новом пустом R-сеансе, чтобы убедиться, что код работает. Люди должны иметь возможность просто скопировать и вставить ваши данные и ваш код в консоль и получить точно такое же, как у вас.

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

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

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

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

Ответ 2

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

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

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

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

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

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

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

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

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

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

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

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

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

Ответ 3

Лично я предпочитаю "один" лайнер. Что-то вроде строк:

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

Ответ 4

Вдохновленный этим самым сообщением, теперь я использую удобную функцию
 reproduce(<mydata>), когда мне нужно отправить сообщение в StackOverflow.


БЫСТРЫЕ ИНСТРУКЦИИ

Если myData - это имя вашего объекта для воспроизведения, запустите в R:

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

reproduce(myData)

Детали:

Эта функция является интеллектуальной оболочкой для dput и выполняет следующие действия:

  • автоматически отображает большой набор данных (в зависимости от размера и класса. Размер выборки можно настроить)
  • создает вывод dput
  • позволяет указать, какие столбцы экспортировать
  • присоединяется к нему objName <- ..., чтобы его можно было легко скопировать + вставить, но...
  • Если вы работаете на Mac, вывод автоматически копируется в буфер обмена, так что вы можете просто запустить его, а затем вставить в свой вопрос.

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


Пример:

# sample data
DF <- data.frame(id=rep(LETTERS, each=4)[1:100], replicate(100, sample(1001, 100)), Class=sample(c("Yes", "No"), 100, TRUE))

DF составляет около 100 x 102. Я хочу пробовать 10 строк и несколько конкретных столбцов

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

Дает следующий вывод:

This is what the sample looks like: 

    id  X1 X73 Class
1    A 266 960   Yes
2    A 373 315    No            Notice the selection split 
3    A 573 208    No           (which can be turned off)
4    A 907 850   Yes
5    B 202  46   Yes         
6    B 895 969   Yes   <~~~ 70 % of selection is from the top rows
7    B 940 928    No
98   Y 371 171   Yes          
99   Y 733 364   Yes   <~~~ 30 % of selection is from the bottom rows.  
100  Y 546 641    No        


    ==X==============================================================X==
         Copy+Paste this part. (If on a Mac, it is already copied!)
    ==X==============================================================X==

 DF <- structure(list(id = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L, 25L, 25L, 25L), .Label = c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y"), class = "factor"), X1 = c(266L, 373L, 573L, 907L, 202L, 895L, 940L, 371L, 733L, 546L), X73 = c(960L, 315L, 208L, 850L, 46L, 969L, 928L, 171L, 364L, 641L), Class = structure(c(2L, 1L, 1L, 2L, 2L, 2L, 1L, 2L, 2L, 1L), .Label = c("No", "Yes"), class = "factor")), .Names = c("id", "X1", "X73", "Class"), class = "data.frame", row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 98L, 99L, 100L)) 

    ==X==============================================================X==

Обратите внимание также, что весь вывод находится в хорошей одиночной, длинной строке, а не в высоком абзаце изрезанных строк. Это облегчает чтение сообщений на SO-сообщениях, а также проще скопировать + вставить.


Обновление октябрь 2013:

Теперь вы можете указать, сколько строк текстового вывода будет занимать (то есть, что вы будете вставлять в 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==

Ответ 5

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

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

EDIT:

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

Ответ 6

В списке рассылки 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")

)

Особенно важно слово small. Вы должны стремиться к минимальному воспроизводимому примеру, что означает, что данные и код должны быть как можно более простыми, чтобы объяснить проблему.

РЕДАКТИРОВАТЬ: Довольно простой код легче читать, чем уродливый код. Используйте руководство по стилю.

Ответ 7

Начиная с версии 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
") 

Ответ 8

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

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

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

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

Ответ 9

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

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


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

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

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


Ответ 10

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

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

>fix(mydata)

When you execute 'fix' command, you will get this pop-up box

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

Ответ 11

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

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

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

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

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

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

Ответ 12

Рекомендация:


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

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

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

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


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

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

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

Посмотрите на SO QA, чтобы найти наборы данных, подходящие для вашей проблемы.

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

Самогенерируемые данные

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

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

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


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

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

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

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


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

Ответ 13

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

Также может потребоваться выборка нескольких переменных вместо всех данных, прежде чем применять команду anonymization и 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

Ответ 14

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

например.

data(mtcars)

а затем выполните задачу

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

Ответ 15

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

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

Вдохновленный @Henrik.

Ответ 16

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

О:

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

Установка:

В настоящее время (2015-06-11), wakefield является пакетом GitHub, но после этого будет отправлен в CRAN после модульных тестов. Для быстрой установки используйте:

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

Пример:

Вот пример:

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

Это дает:

    ID  Race Age    Sex     Hour  IQ Height  Died
1  001 White  33   Male 00:00:00 104     74  TRUE
2  002 White  24   Male 00:00:00  78     69 FALSE
3  003 Asian  34 Female 00:00:00 113     66  TRUE
4  004 White  22   Male 00:00:00 124     73  TRUE
5  005 White  25 Female 00:00:00  95     72  TRUE
6  006 White  26 Female 00:00:00 104     69  TRUE
7  007 Black  30 Female 00:00:00 111     71 FALSE
8  008 Black  29 Female 00:00:00 100     64  TRUE
9  009 Asian  25   Male 00:30:00 106     70 FALSE
10 010 White  27   Male 00:30:00 121     68 FALSE
.. ...   ... ...    ...      ... ...    ...   ...

Ответ 17

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

dput(droplevels(head(mydata)))

Ответ 18

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

Ответ 19

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

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

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

Ответ 20

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

Ответ 21

Вы можете сделать это, используя reprex.

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

Согласно Tidyverse:

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

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

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

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

Ответ 22

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

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

    • Имейте некоторый набор данных
    • Попробуйте описать требуемый результат как можно проще
    • Сделайте это самостоятельно, прежде чем задавать вопрос
  • Легко загрузить изображение, поэтому загрузите сюжеты, если у вас есть
  • Также укажите любые ошибки, которые могут возникнуть

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

Ответ 23

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

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

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