Как сделать отличный R воспроизводимый пример
При обсуждении производительности с коллегами, обучении, отправке отчета об ошибках или поиске руководства в списках рассылки и здесь, в Переполнении стека, часто задают воспроизводимый пример и всегда помогают.
Каковы ваши советы по созданию отличного примера? Как вы вставляете структуры данных из r в текстовом формате? Какую другую информацию вы должны включить?
Есть ли другие хитрости в дополнение к использованию dput()
, dump()
или же structure()
? Когда вы должны включить library()
или же require()
заявления? Какие зарезервированные слова следует избегать, в дополнение к c
, df
, data
, так далее.?
Как сделать великолепный воспроизводимый пример?
23 ответа
Минимальный воспроизводимый пример состоит из следующих элементов:
- минимальный набор данных, необходимый для воспроизведения ошибки
- минимальный исполняемый код, необходимый для воспроизведения ошибки, который может быть запущен для данного набора данных.
- необходимая информация об используемых пакетах, версии R и системе, в которой она запущена.
- в случае случайных процессов, семя (устанавливается
set.seed()
) для воспроизводимости
Глядя на примеры в файлах справки используемых функций, часто бывает полезно. В общем, весь приведенный там код отвечает требованиям минимального воспроизводимого примера: данные предоставляются, минимальный код предоставляется, и все работает.
Создание минимального набора данных
В большинстве случаев это легко сделать, просто предоставив вектор / фрейм данных с некоторыми значениями. Или вы можете использовать один из встроенных наборов данных, которые поставляются с большинством пакетов.
Полный список встроенных наборов данных можно увидеть с 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")
,
(Вот мой совет от Как написать воспроизводимый пример. Я попытался сделать его коротким, но приятным)
Как написать воспроизводимый пример.
Скорее всего, вы получите хорошую помощь по проблеме R, если предоставите воспроизводимый пример. Воспроизводимый пример позволяет кому-то другому воссоздать вашу проблему, просто скопировав и вставив код R.
Чтобы сделать ваш пример воспроизводимым, нужно включить четыре вещи: необходимые пакеты, данные, код и описание вашей среды R.
Пакеты должны быть загружены в верхней части скрипта, поэтому легко увидеть, какие из них нужны в примере.
Самый простой способ включить данные в электронное письмо или вопрос переполнения стека - это использовать
dput()
генерировать код R, чтобы воссоздать его. Например, чтобы воссоздатьmtcars
Набор данных в R, я бы выполнил следующие шаги:- Бежать
dput(mtcars)
в R - Скопируйте вывод
- В моем воспроизводимом скрипте введите
mtcars <-
затем вставьте.
- Бежать
Потратьте немного времени, чтобы ваш код легко читался другими:
убедитесь, что вы использовали пробелы и имена переменных краткие, но информативные
используйте комментарии, чтобы указать, где ваша проблема лежит
сделать все возможное, чтобы удалить все, что не связано с проблемой.
Чем короче ваш код, тем легче его понять.
Включить вывод
sessionInfo()
в комментарии в вашем коде. Это суммирует вашу среду R и позволяет легко проверить, используете ли вы устаревший пакет.
Вы можете проверить, действительно ли вы создали воспроизводимый пример, запустив новый сеанс R и вставив в него скрипт.
Прежде чем поместить весь свой код в электронное письмо, рассмотрите возможность размещения его на Gist GitHub. Это даст вашему коду хорошую подсветку синтаксиса, и вам не придется беспокоиться о том, что система электронной почты может что-то испортить.
Лично я предпочитаю "один" лайнер. Нечто подобное:
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 shapefile) в "пространственных" пакетах (см. Пространственное представление в представлениях задач).
library(rgdal)
ogrDrivers()
dsn <- system.file("vectors", package = "rgdal")[1]
ogrListLayers(dsn)
ogrInfo(dsn=dsn, layer="cities")
cities <- readOGR(dsn=dsn, layer="cities")
Вдохновленный этим постом, я теперь использую удобную функциюreproduce(<mydata>)
когда мне нужно опубликовать в Stackru.
БЫСТРЫЕ ИНСТРУКЦИИ
Если 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 х 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:
Теперь вы можете указать, сколько строк текста будет занимать (то есть, что вы будете вставлять в Stackru). Использовать 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==
Вот хорошее руководство:
http://www.r-bloggers.com/three-tips-for-posting-good-questions-to-r-help-and-stack-overflow/
Но самое важное: просто убедитесь, что вы создали небольшой фрагмент кода, который мы можем запустить, чтобы увидеть, в чем проблема. Полезная функция для этого dput()
, но если у вас очень большие данные, вы можете создать небольшой набор данных или использовать только первые 10 строк или около того.
РЕДАКТИРОВАТЬ:
Также убедитесь, что вы сами определили, где проблема. Примером не должен быть весь сценарий R с надписью "В строке 200 произошла ошибка". Если вы используете инструменты отладки в R (я люблю browser()
) и Google, вы должны быть в состоянии действительно определить, где проблема и воспроизвести тривиальный пример, в котором то же самое идет не так.
В списке рассылки R-help есть руководство по отправке, которое охватывает как вопросы, так и ответы, включая пример создания данных:
Примеры: иногда это помогает привести небольшой пример, который кто-то может запустить. Например:
Если у меня есть матрица х следующим образом:
> 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")
)
Слово маленькое особенно важно. Вы должны стремиться к минимальному воспроизводимому примеру, что означает, что данные и код должны быть максимально простыми, чтобы объяснить проблему.
РЕДАКТИРОВАТЬ: красивый код легче читать, чем уродливый код. Используйте руководство по стилю.
Начиная с R.2.14 (я полагаю), вы можете передать свое текстовое представление данных непосредственно в 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
")
Иногда проблема на самом деле не воспроизводима с небольшим фрагментом данных, независимо от того, как сильно вы пытаетесь, и не возникает с синтетическими данными (хотя полезно показать, как вы создали синтетические наборы данных, которые не воспроизводили проблему, потому что это исключает некоторые гипотезы).
- Публикация данных в Интернете где-то и предоставление URL может быть необходимым.
- Если данные не могут быть предоставлены широкой публике, но могут быть переданы вообще, то вы можете предложить заинтересованным сторонам отправить их по электронной почте (хотя это сократит количество людей, которые потрудятся работать в теме).
- На самом деле я не видел, чтобы это было сделано, потому что люди, которые не могут выпустить свои данные, чувствительны к тому, чтобы выпустить их в любой форме, но кажется вероятным, что в некоторых случаях все еще можно публиковать данные, если они были достаточно анонимными / скремблированными / слегка поврежденными. каким-то образом.
Если вы не можете сделать ни то, ни другое, вам, вероятно, нужно нанять консультанта, чтобы решить вашу проблему...
редактировать: два полезных вопроса для анонимизации / шифрования:
Ответы до сих пор, очевидно, хороши для воспроизводимости. Это просто для того, чтобы прояснить, что воспроизводимый пример не может и не должен быть единственным компонентом вопроса. Не забудьте объяснить, как вы хотите, чтобы он выглядел, и контуры вашей проблемы, а не только то, как вы пытались добраться до сих пор. Код не достаточно; тебе тоже нужны слова.
Вот воспроизводимый пример того, чего следует избегать (взятый из реального примера, имена изменены, чтобы защитить невинных):
Ниже приведены примеры данных и часть функций, с которыми у меня возникли проблемы.
code
code
code
code
code (40 or so lines of it)
Как мне этого добиться?
У меня есть очень простой и эффективный способ сделать R пример, который не был упомянут выше. Вы можете определить свою структуру в первую очередь. Например,
mydata <- data.frame(a=character(0), b=numeric(0), c=numeric(0), d=numeric(0))
>fix(mydata)
Затем вы можете ввести свои данные вручную. Это эффективно для небольших примеров, а не для больших.
Методические рекомендации:
Ваша главная цель при составлении ваших вопросов должна состоять в том, чтобы сделать читателей как можно более легкими для понимания и воспроизведения вашей проблемы в своих системах. Для этого:
- Предоставить входные данные
- Обеспечить ожидаемый результат
- Объясните свою проблему кратко
- если у вас более 20 строк текста + код, вы можете вернуться и упростить
- максимально упростите ваш код, сохраняя проблему / ошибку
Это требует некоторой работы, но кажется справедливым компромиссом, поскольку вы просите других сделать работу за вас.
Предоставление данных:
Встроенные наборы данных
Наилучшим вариантом на сегодняшний день является использование встроенных наборов данных. Это позволяет другим легко работать над вашей проблемой. Тип data()
на приглашение R, чтобы увидеть, какие данные доступны для вас. Несколько классических примеров:
iris
mtcars
ggplot2::diamonds
(внешний пакет, но почти у всех есть)
Посмотрите этот SO QA, чтобы узнать, как найти наборы данных, подходящие для вашей проблемы.
Если вы можете перефразировать свою проблему, используя встроенные наборы данных, у вас гораздо больше шансов получить хорошие ответы (и положительные отзывы).
Собственные данные
Если ваша проблема очень специфична для типа данных, которые не представлены в существующих наборах данных, предоставьте код R, который генерирует наименьший возможный набор данных, в котором ваша проблема проявляется. Например
set.seed(1) # important to make random data reproducible
myData <- data.frame(a=sample(letters[1:5], 20, rep=T), b=runif(20))
Теперь кто-то, пытающийся ответить на мой вопрос, может скопировать / вставить эти две строки и немедленно начать работу над проблемой.
dput
В крайнем случае, вы можете использовать dput
преобразовать объект данных в код R (например, dput(myData)
). Я говорю как "последнее средство", потому что выход dput
часто довольно громоздкий, раздражающий копировать-вставить, и затеняет остальную часть вашего вопроса.
Обеспечить ожидаемый результат:
Кто-то однажды сказал:
Картина ожидаемого результата стоит 1000 слов
- очень мудрый человек
Если вы можете добавить что-то вроде "Я ожидал получить этот результат":
cyl mean.hp
1: 6 122.28571
2: 4 82.63636
3: 8 209.21429
на ваш вопрос, люди с большей вероятностью быстро поймут, что вы пытаетесь сделать. Если ожидаемый результат является большим и громоздким, то вы, вероятно, недостаточно задумывались о том, как упростить вашу проблему (см. Далее)
Объясните свою проблему кратко
Главное, чтобы максимально упростить вашу проблему, прежде чем задавать вопрос. Перефразирование проблемы для работы со встроенными наборами данных очень поможет в этом отношении. Вы также часто обнаружите, что, пройдя процесс упрощения, вы решите свою собственную проблему.
Вот несколько примеров хороших вопросов:
В обоих случаях проблемы пользователя почти наверняка не связаны с простыми примерами, которые они предоставляют. Скорее они абстрагировали природу своей проблемы и применили ее к простому набору данных, чтобы задать свой вопрос.
Почему еще один ответ на этот вопрос?
Этот ответ сфокусирован на том, что я считаю лучшей практикой: используйте встроенные наборы данных и предоставьте то, что вы ожидаете в результате, в минимальной форме. Наиболее выдающиеся ответы сосредоточены на других аспектах. Я не ожидаю, что этот ответ поднимется до какой-то известности; это здесь исключительно для того, чтобы я мог ссылаться на него в комментариях к вопросам новичка.
Чтобы быстро создать dput
ваших данных вы можете просто скопировать (часть) данных в буфер обмена и запустить следующее в R:
для данных в Excel:
dput(read.table("clipboard",sep="\t",header=TRUE))
для данных в текстовом файле:
dput(read.table("clipboard",sep="",header=TRUE))
Вы можете изменить sep
в последнем случае, если это необходимо. Это будет работать, только если ваши данные находятся в буфере обмена, конечно.
Воспроизводимый код - это ключ к получению помощи. Однако есть много пользователей, которые скептически относятся к вставке даже части своих данных. Например, они могут работать с конфиденциальными данными или с исходными данными, собранными для использования в исследовательской работе. По какой-то причине я подумал, что было бы неплохо иметь удобную функцию для "деформации" моих данных перед их публичным вставлением. 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
Часто вам нужны некоторые данные для примера, однако вы не хотите публиковать свои точные данные. Чтобы использовать некоторые существующие data.frame в установленной библиотеке, используйте команду data для их импорта.
например,
data(mtcars)
а затем сделать проблему
names(mtcars)
your problem demostrated on the mtcars data set
Я разрабатываю пакет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
.. ... ... ... ... ... ... ... ...
Если у вас есть один или несколько factor
переменные в ваших данных, которые вы хотите сделать воспроизводимыми с dput(head(mydata))
рассмотреть возможность добавления droplevels
к этому, так что уровни факторов, которые не присутствуют в минимизированном наборе данных, не включены в ваш dput
вывод, чтобы сделать пример минимальным:
dput(droplevels(head(mydata)))
Интересно, может ли ссылка http://old.r-fiddle.org/ быть очень аккуратным способом поделиться проблемой. Он получает уникальный идентификатор типа, и можно даже подумать о встраивании его в SO.
Пожалуйста, не вставляйте выходные данные вашей консоли, как это:
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")
Еще одна вещь, если вы использовали какую-либо функцию из определенного пакета, упомяните эту библиотеку.
Вы можете сделать это с использованием представительства.
Как отметил mt1022, "... хорошим пакетом для создания минимального, воспроизводимого примера является " представитель " от tidyverse".
По словам Тидиверса:
Цель "представительства" состоит в том, чтобы упаковать ваш проблемный код таким образом, чтобы другие люди могли его запустить и почувствовать вашу боль.
Пример приведен на сайте Tidyverse.
library(reprex)
y <- 1:4
mean(y)
reprex()
Я думаю, что это самый простой способ создать воспроизводимый пример.
Помимо всех вышеупомянутых ответов, которые я нашел очень интересными, иногда это может быть очень легко, как это обсуждается здесь:- КАК СДЕЛАТЬ МИНИМАЛЬНЫЙ ВОСПРОИЗВОДИМЫЙ ПРИМЕР, ЧТОБЫ ПОЛУЧИТЬ ПОМОЩЬ С R
Есть много способов сделать случайный вектор Создать вектор из 100 чисел со случайными значениями в R, округленными до 2 десятичных знаков или случайной матрицей в R
mydf1<- matrix(rnorm(20),nrow=20,ncol=5)
Обратите внимание, что иногда очень сложно обмениваться данными из-за различных причин, таких как размерность и т. Д. Однако все вышеприведенные ответы очень полезны и очень важны для размышления и использования, когда требуется создать пример воспроизводимых данных. Но учтите, что для того, чтобы сделать данные такими же репрезентативными, как и исходные (в случае, если ОП не может предоставить исходные данные совместно), полезно добавить некоторую информацию в пример данных как (если мы назовем данные 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))
Вот некоторые из моих предложений:
- Попробуйте использовать наборы данных R по умолчанию
- Если у вас есть собственный набор данных, включите их в
dput
так что другие могут помочь вам легче - Не использовать
install.package()
если это действительно необходимо, люди поймут, если вы просто используетеrequire
или жеlibrary
Постарайся быть кратким,
- Есть какой-то набор данных
- Постарайтесь описать нужный вам результат как можно проще
- Сделай сам, прежде чем задать вопрос
- Загрузить изображение легко, поэтому загружайте графики, если у вас есть
- Также включите любые ошибки, которые могут у вас возникнуть
Все это является частью воспроизводимого примера.
Это хорошая идея, чтобы использовать функции из 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
позволяет вашему помощнику сосредоточиться на коде, что экономит время и дает им возможность узнать, что они решили вашу проблему, прежде чем они отправят его