如何制作出色的 R 可重现示例

How to make a great R reproducible example

提问人: 提问时间:5/11/2011 最后编辑:15 revs, 10 users 41%Hack-R 更新时间:8/18/2023 访问量:451444

问:

这个问题的答案是社区的努力。编辑现有答案以改进此帖子。它目前不接受新的答案或交互。

在与同事讨论性能、教学、发送错误报告或在邮件列表和 Stack Overflow 上搜索指导时,经常会问到一个可重现的例子,而且总是有帮助的。

你有什么技巧来创造一个优秀的例子?如何以文本格式粘贴 中的数据结构?您还应该包括哪些其他信息?

除了使用 ,或者 还有其他技巧吗?什么时候应该包括 OR 语句?除了 、 、 等之外,还应该避免哪些保留词?dput()dump()structure()library()require()cdfdata

如何制作一个伟大的 可重复的例子?

R-常见问题

评论

34赞 baptiste 8/7/2011
我对问题的范围感到困惑。人们似乎在对 SO 或 R-help(如何“重现错误”)提出问题时跳上了可重现示例的解释。帮助页面中的可重现 R 示例怎么样?在软件包演示中?在教程/演示文稿中?
15赞 Joris Meys 10/4/2011
@baptiste:相同减去错误。我解释的所有技术都用于包帮助页面,以及我提供的有关 R 的教程和演示文稿中
33赞 Etienne Low-Décarie 5/12/2012
数据有时是限制因素,因为结构可能过于复杂而无法模拟。从私有数据生成公共数据:stackoverflow.com/a/10458688/742447 stackoverflow.com/questions/10454973/...

答:

226赞 4 revs, 3 users 60%Sacha Epskamp #1

这是一个很好的指南

最重要的一点是:制作一小段代码,我们可以运行它来查看问题所在。一个有用的函数是 ,但是如果您有非常大的数据,那么您可能希望创建一个小型样本数据集或仅使用前 10 行左右。dput()

编辑:

此外,请确保您自己确定了问题所在。该示例不应是包含“第 200 行出现错误”的整个 R 脚本。如果你使用 R(我喜欢)和 Google 中的调试工具,那么你应该能够真正确定问题所在,并重现一个同样的事情出错的微不足道的例子。browser()

346赞 4 revs, 3 users 93%Roman Luštrik #2

就个人而言,我更喜欢“一个”班轮。类似的东西:

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)

如果需要 中实现的一些空间对象,可以通过“空间”包中的外部文件(如 ESRI shapefile)获取一些数据集(请参阅任务视图中的空间视图)。sp

library(rgdal)
ogrDrivers()
dsn <- system.file("vectors", package = "rgdal")[1]
ogrListLayers(dsn)
ogrInfo(dsn=dsn, layer="cities")
cities <- readOGR(dsn=dsn, layer="cities")
1969赞 31 revs, 19 users 43%Joris Meys #3

基本上,最小可重现示例 (MRE) 应该使其他人能够在他们的机器上准确地重现您的问题。

请不要发布您的数据、代码或控制台输出的图像!

小结

MRE由以下项目组成:

  • 最小的数据集,用于演示问题
  • 重现问题所需的最小可运行代码,可以在给定数据集上运行
  • 有关所用 s、R 版本和运行它的操作系统的所有必要信息,也许是一个librarysessionInfo()
  • 在随机过程的情况下,种子(由 设置)使其他人能够复制与您完全相同的结果set.seed()

有关良好 MRE 的示例,请参阅帮助页面底部有关您正在使用的函数的“示例”部分。只需键入 例如,或短输入 R 控制台即可。help(mean)?mean

提供最小的数据集

通常,共享庞大的数据集是没有必要的,反而可能会阻止其他人阅读您的问题。因此,最好使用内置数据集或创建一个类似于原始数据的小“玩具”示例,这实际上是最小值的意思。如果出于某种原因您确实需要共享原始数据,则应使用一种方法,例如 ,该方法允许其他人获取您数据的精确副本。dput()

内置数据集

您可以使用其中一个内置数据集。可以使用 查看内置数据集的完整列表。每个数据集都有简短的描述,并且可以获得更多信息,例如,对于 R 附带的“虹膜”数据集,已安装的软件包可能包含其他数据集。data()?iris

创建示例数据集

初步说明:有时您可能需要特殊格式(即类),例如因子、日期或时间序列。对于这些,请使用以下功能:、、、......例:as.factoras.Dateas.xts

d <- as.Date("2020-12-30")

哪里

class(d)
# [1] "Date"

向量

x <- rnorm(10)  ## random vector normal distributed
x <- runif(10)  ## random vector uniformly distributed    
x <- sample(1:100, 10)  ## 10 random draws out of 1, 2, ..., 100    
x <- sample(LETTERS, 10)  ## 10 random draws out of built-in latin alphabet

矩阵

m <- matrix(1:12, 3, 4, dimnames=list(LETTERS[1:3], LETTERS[1:4]))
m
#   A B C  D
# A 1 4 7 10
# B 2 5 8 11
# C 3 6 9 12

数据框

set.seed(42)  ## for sake of reproducibility
n <- 6
dat <- data.frame(id=1:n, 
                  date=seq.Date(as.Date("2020-12-26"), as.Date("2020-12-31"), "day"),
                  group=rep(LETTERS[1:2], n/2),
                  age=sample(18:30, n, replace=TRUE),
                  type=factor(paste("type", 1:n)),
                  x=rnorm(n))
dat
#   id       date group age   type         x
# 1  1 2020-12-26     A  27 type 1 0.0356312
# 2  2 2020-12-27     B  19 type 2 1.3149588
# 3  3 2020-12-28     A  20 type 3 0.9781675
# 4  4 2020-12-29     B  26 type 4 0.8817912
# 5  5 2020-12-30     A  26 type 5 0.4822047
# 6  6 2020-12-31     B  28 type 6 0.9657529

注意:尽管它被广泛使用,但最好不要将数据框命名为 df,因为 df() 是 F 分布的密度(即 x 点处曲线的高度)的 R 函数,您可能会与它发生冲突。

复制原始数据

如果您有特定原因,或者数据太难从中构建示例,则可以提供原始数据的一小部分,最好使用 .dput

为什么要使用 dput()

dput抛出在控制台上准确再现数据所需的所有信息。您可以简单地复制输出并将其粘贴到您的问题中。

调用(从上面)生成的输出仍然缺少有关变量类和其他功能的信息,如果您在问题中共享它。此外,列中的空格使得很难对它做任何事情。即使我们开始使用数据,我们也无法正确获取数据的重要特征。dattype

  id       date group age   type         x
1  1 2020-12-26     A  27 type 1 0.0356312
2  2 2020-12-27     B  19 type 2 1.3149588
3  3 2020-12-28     A  20 type 3 0.9781675

子集数据

要共享子集,请使用 或 索引 。然后把它包装进去,给其他人一些可以立即放入 R 中的东西。head()subset()iris[1:4, ]dput()

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")), row.names = c(NA, 
4L), class = "data.frame")

使用 时,您可能还希望仅包含相关列,例如 dput(mtcars[1:3, c(2, 5, 6)])dput

注意:如果数据框具有具有多个级别的因子,则 dput 输出可能很笨拙,因为它仍将列出所有可能的因子级别,即使它们不存在于数据子集中。要解决此问题,您可以使用 droplevels() 函数。请注意下面的物种如何是一个只有一个水平的因子,例如 dput(droplevels(iris[1:4, ])))。dput 的另一个警告是,它不适用于键控 data.table 对象或来自 tidyverse 的分组tbl_df类 grouped_df)。在这些情况下,您可以在共享之前转换回常规数据框 dput(as.data.frame(my_data))。

生成最少的代码

结合最少的数据(见上文),您的代码应该只需复制和粘贴即可在另一台计算机上准确地重现问题。

这应该是容易的部分,但往往不是。你不应该做什么:

  • 显示各种数据转换;确保提供的数据已经采用正确的格式(当然,除非这是问题所在)
  • 复制粘贴在某处出现错误的整个脚本。尝试找到导致错误的确切行。通常情况下,您会自己发现问题出在哪里。

你应该做什么:

  • 添加您使用的软件包(如果您使用任何包(使用library())
  • test 在新的 R 会话中运行代码,以确保代码可运行。人们应该能够在控制台中复制粘贴您的数据和代码,并获得与您相同的数据和代码。
  • 如果打开连接或创建文件,请添加一些代码以关闭它们或删除文件(使用unlink())
  • 如果更改选项,请确保代码包含语句以将其还原为原始选项。(例如op <- par(mfrow=c(1,2)) ...some code... par(op) )

提供必要的信息

在大多数情况下,只有 R 版本和操作系统就足够了。当包发生冲突时,提供 的输出确实会有所帮助。在谈论与其他应用程序的连接(无论是通过ODBC还是其他任何应用程序)时,还应该提供这些应用程序的版本号,如果可能的话,还应该提供有关设置的必要信息。sessionInfo()

如果在 R Studio 中运行 R,则使用 可以帮助报告 RStudio 版本。rstudioapi::versionInfo()

如果对特定软件包有疑问,则可能需要通过提供 的输出来提供软件包版本。packageVersion("name of the package")

种子

使用 u 可以指定一个种子1,即 R 的随机数生成器固定的特定状态。这使得随机函数(如 、 和许多其他函数)始终返回相同的结果成为可能, 示例:set.seed()sample()rnorm()runif()

set.seed(42)
rnorm(3)
# [1]  1.3709584 -0.5646982  0.3631284

set.seed(42)
rnorm(3)
# [1]  1.3709584 -0.5646982  0.3631284

1 注意:set.seed() 的输出在 R >3.6.0 和以前的版本之间有所不同。指定用于随机过程的 R 版本,如果在回答旧问题时得到的结果略有不同,请不要感到惊讶。在这种情况下,要获得相同的结果,您可以在 set.seed() 之前使用 RNGversion() 函数(例如:RNGversion(“3.5.2”))。

评论

1赞 EngrStudent 8/3/2023
我个人的喜好之一:我喜欢 Knuth 的识字编程的变体。变量和操作需要在代码注释或文本中描述。
191赞 2 revsRichie Cotton #4

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 行,有 3 列,名为 '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")

)

“小”这个词尤为重要。您应该以最小的可重现示例为目标,这意味着数据和代码应该尽可能简单地解释问题。

编辑:漂亮的代码比丑陋的代码更容易阅读。使用风格指南

652赞 10 revs, 9 users 76%hadley #5

(这是我的建议 如何编写一个可重现的例子.我试着让它简短但甜蜜。r4ds 中的“工作流:获取帮助”的第 9.2 节是最近的一个版本,其中也讨论了 reprex 包。

如何编写可重现的示例

如果你提供一个可重现的示例,你最有可能在R问题上得到很好的帮助。可重现的示例允许其他人通过复制和粘贴 R 代码来重现你的问题。

若要使示例可重现,需要包含四项内容:必需的包、数据、代码和 R 环境的说明。

  • 应该加载在脚本的顶部,这样很容易 查看示例需要哪些。

  • 在电子邮件或 Stack Overflow 问题中包含数据的最简单方法是用于生成 R 代码以重新创建它。例如,若要在 R 中重新创建数据集, 我将执行以下步骤:dput()mtcars

    1. 在 R 中运行dput(mtcars)
    2. 复制输出
    3. 在我的可重现脚本中,键入然后粘贴。mtcars <-
  • 花一点时间确保你的代码对其他人来说很容易 读:

    • 确保您使用了空格,并且变量名称简洁,但 信息

    • 使用注释来指出问题所在

    • 尽最大努力删除与问题无关的所有内容。
      代码越短,越容易理解。

  • 在代码的注释中包含 的输出。这总结了你的 R 环境,并可以轻松检查您是否正在使用过时的 包。sessionInfo()

可以通过启动新的 R 会话并粘贴脚本来检查是否确实制作了可重现的示例。

在将所有代码放入电子邮件之前,请考虑将其放在 Gist github 上。它将为您的代码提供很好的语法突出显示,并且您不必担心电子邮件系统会破坏任何事情。

评论

38赞 mt1022 6/1/2017
reprexin 是一个很好的包,用于生成最小的、可重复的示例:github.com/tidyverse/reprextidyverse
29赞 hadley 3/4/2018
我经常收到包含代码的电子邮件。我什至收到带有包含代码的附加 word 文档的电子邮件。有时我甚至会收到带有附加 word 文档的电子邮件,其中包含代码截图。
0赞 Grace 7/30/2020
如果它是一个图形对象呢? 不幸的是,对于图形,返回一长行向量。dput()
0赞 Francis Barton 4/14/2021
与空间数据(如抖音)相同。即使被削减到只有几行,根据我的经验,这些似乎也不能很好地与这样的工具配合使用。sfdput
0赞 Julien 8/17/2022
如何将输出直接复制到Windows中的剪贴板?dput(mtcars)
166赞 4 revsBen Bolker #6

有时,无论您多么努力,问题都无法用较小的数据重现,并且不会发生在合成数据中(尽管展示您如何生成重现问题的合成数据集很有用,因为它排除了一些假设)。

  • 可能需要将数据发布到网络某处并提供 URL。
  • 如果数据不能向公众发布,但可以共享,那么你可以提出通过电子邮件将其发送给感兴趣的各方(尽管这将减少费心处理它的人数)。
  • 我实际上还没有看到这样做,因为无法发布数据的人对以任何形式发布数据都很敏感,但在某些情况下,如果数据被充分匿名化/扰乱/以某种方式略微损坏,人们仍然可以发布数据,这似乎是合理的。

如果你不能做到这些,那么你可能需要聘请顾问来解决你的问题......

编辑:匿名/加扰的两个有用的 SO 问题:

评论

3赞 Iterator 10/23/2011
为了生成合成数据集,这个问题的答案给出了有用的示例,包括 和 的应用。fitdistrfitdistrplus
0赞 Francis Barton 4/14/2021
我真的很想得到一些关于提供示例空间数据的建议,例如在几何列中具有大量坐标的 sf tibble。这些似乎没有使用 dput 完全复制到剪贴板,即使只有几行数据。有一些内置的 sf 数据集可以在 reprex 中使用,但有时有必要提供自己的数据样本,因为正是这些数据导致了这个问题
189赞 2 revs, 2 users 78%Paolo #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
") 
155赞 2 revsAri B. Friedman #8

到目前为止,答案显然对可重复性部分很好。这只是为了澄清,一个可重复的例子不能也不应该成为问题的唯一组成部分。不要忘记解释你希望它是什么样子以及你的问题的轮廓,而不仅仅是你到目前为止是如何试图到达那里的。光有代码是不够的;你也需要言语。

这是一个可重复的例子,说明要避免做什么(取自一个真实的例子,为了保护无辜者而改名):


以下是示例数据和部分功能,我有问题。

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

我怎样才能做到这一点?


117赞 userJT #9

通常,您需要一些数据作为示例,但是,您不想发布确切的数据。要使用已建立库中的某些现有 data.frame,请使用 data 命令导入它。

例如,

data(mtcars)

然后做问题

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

评论

15赞 Gregor Thomas 7/18/2013
许多内置数据集(如热门数据集和数据集)实际上并不需要使用调用。mtcarsirisdata
138赞 3 revs, 2 users 77%Jonas Tundo #10

若要快速创建数据,只需将数据复制到剪贴板,然后在 R 中运行以下命令:dput

对于 Excel 中的数据:

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

对于 .txt 文件中的数据:

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

如有必要,您可以更改后者。 当然,这只有在您的数据位于剪贴板中时才有效。sep

321赞 13 revs, 5 users 62%Ricardo Saporta #11

受到这篇文章的启发,当我需要发布到 Stack Overflow 时,我现在使用了一个方便的功能。reproduce(<mydata>)


快速说明

如果是要重现的对象的名称,请在 R 中运行以下命令:myData

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

还要注意的是,整个输出都是一条漂亮的长线,而不是一大段切碎的线。 这使得在 Stack Overflow 问题帖子上更容易阅读,也更容易复制 + 粘贴。


2013年10月更新:

您现在可以指定将占用多少行文本输出(即,您将粘贴到 Stack Overflow 中的内容)。为此使用参数。例: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==

评论

1赞 Julien 7/23/2022
是否必须在每个会话中运行才能使用该功能?library(devtools);source_url("https://raw.github.com/rsaporta/pubR/gitbranch/reproduce.R")reproduce
0赞 Julien 7/23/2022
不幸的是,控制台中的输出数据不在一行中,至少对我来说是这样 Windows 11
0赞 Julien 8/17/2022
要在一行中复制 的输出,请运行dputwriteClipboard(paste(capture.output(dput(DF)), collapse = ""))
108赞 3 revs, 3 users 67%Tomas #12

如果你有一个大型数据集,不能轻松地用 将你的数据发布到pastebin,并使用以下命令加载它们:dput()read.table

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

灵感来自亨里克

144赞 3 revs, 3 users 81%jasmine_007 #13

我有一种非常简单有效的方法来制作上面没有提到的 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

然后,您可以手动输入数据。这对于较小的示例而不是大型示例是有效的。

评论

24赞 GSee 3/9/2014
...然后dput(mydata)
0赞 Léo Léopold Hertz 준영 10/30/2016
你的前端是什么?如果能有一个完整的答案就好了。等等,制作一个可以直接循环的数据,比如。for (d in data) {...}
136赞 5 revs, 3 users 60%daniel #14

可重现的代码是获得帮助的关键。但是,有许多用户可能对粘贴他们的数据块持怀疑态度。例如,他们可能正在处理敏感数据或收集的原始数据以用于研究论文。

无论出于何种原因,我认为在公开粘贴数据之前有一个方便的功能来“变形”我的数据会很好。包中的功能非常愚蠢,但对我来说,它与该功能配合得很好。anonymizeSciencesPodput

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
74赞 3 revsCMichael #15

原来的帖子指的是 datacamp 现已退役的 r-fiddle 服务。它已被重新命名为 datacamp light,并且不能像我的回答所示那样容易嵌入。

我想知道 http://old.r-fiddle.org/ 链接是否可以成为分享问题的一种非常简洁的方式。它接收一个唯一的 ID,甚至可以考虑将其嵌入到 SO 中。

评论

1赞 Julien 7/14/2022
这个网站看起来很慢
0赞 Julien 8/17/2022
你能解释一下它是如何工作的吗?
0赞 CMichael 9/1/2022
他们停用了这项服务,它不再有用。更新答案以解决此问题。
85赞 2 revsdocendo discimus #16

如果数据中有一个或多个变量要使其可重现,请考虑将其添加到该变量中,以便输出中不包含最小化数据集中不存在的因子级别,以使示例最小化:factordput(head(mydata))droplevelsdput

dput(droplevels(head(mydata)))
138赞 10 revs, 6 users 62%BrodieG #17

指引:


您制定问题的主要目标应该是让读者尽可能容易地理解并在他们的系统上重现您的问题。为此,请执行以下操作:

  1. 提供输入数据
  2. 提供预期输出
  3. 简明扼要地解释您的问题
    • 如果你有超过 20 行文本 + 代码,你也许可以回去简化
    • 尽可能简化代码,同时保留问题/错误

这确实需要一些工作,但这似乎是一个公平的权衡,因为你要求别人为你做工作。

提供数据:


内置数据集

到目前为止,最好的选择是依赖内置数据集。这使其他人很容易解决您的问题。在 R 提示符下键入以查看可用的数据。一些经典的例子:data()

  • 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

作为最后的手段,您可以使用将数据对象转换为 R 代码(例如)。我之所以说是“最后的手段”,是因为输出通常相当笨拙,复制粘贴很烦人,并且掩盖了您问题的其余部分。dputdput(myData)dput

提供预期输出:


有人曾经说过:

一张预期输出的图片胜过 1000 字

-- 一个有贤的人

如果您可以添加类似“我期望得到此结果”的内容:

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

对于你的问题,人们更有可能快速理解你想做什么。如果你的预期结果很大而且笨拙,那么你可能还没有充分考虑如何简化你的问题(见下文)。

简明扼要地解释您的问题


最主要的是在提出问题之前尽可能简化您的问题。在这方面,重新构建问题以使用内置数据集将有很大帮助。你也会经常发现,只要经历简化的过程,你就会回答自己的问题。

以下是一些好问题的例子:

在这两种情况下,用户的问题几乎肯定不在于他们提供的简单示例。相反,他们抽象了问题的本质,并将其应用于一个简单的数据集来提出他们的问题。

为什么这个问题又要回答呢?


这个答案侧重于我认为的最佳实践:使用内置数据集,并以最小的形式提供您期望的结果。最突出的答案集中在其他方面。我不指望这个答案会上升到任何突出地位;这只是为了让我可以在新手问题的评论中链接到它。

102赞 Tyler Rinker #18

我正在开发 wakefield 软件包来满足快速共享可重现数据的需求,有时适用于较小的数据集,但我们处理的许多问题要大得多,通过共享如此大的数据集是不切实际的。dputdput

大约:

Wakefield 允许用户共享最少的代码来重现数据。用户设置(行数)并指定任意数量的预设变量函数(目前有 70 个),这些函数模仿真实的 if 数据(如性别、年龄、收入等)。n

安装:

目前 (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
.. ...   ... ...    ...      ... ...    ...   ...
34赞 3 revs, 2 users 84%TheRimalaya #19

以下是我的一些建议:

  • 尝试使用默认的 R 数据集
  • 如果您有自己的数据集,请将它们包含在 中,以便其他人可以更轻松地为您提供帮助dput
  • 除非真的有必要,否则不要使用,如果你只是使用或install.package()requirelibrary
  • 尽量简明扼要,

    • 有一些数据集
    • 尝试尽可能简单地描述您需要的输出
    • 在你问问题之前自己动手
  • 上传图像很容易,所以如果你有,请上传绘图
  • 还要包括您可能遇到的任何错误

所有这些都是可重现示例的一部分。

评论

2赞 Rich Scriven 4/10/2016
你在这里没有真正添加任何实质性的东西。 前面已经提到过,其中大部分只是重申标准的 SO 准则。dput()
2赞 TheRimalaya 4/10/2016
我在示例中包含的功能方面遇到了问题,这并不是真正必要的(在我看来)。此外,使用默认的 R 数据集将使可重现性更容易。SO 指南没有具体讨论这些主题。此外,它旨在发表我的意见,这些是我遇到最多的一个。install.package
41赞 6 revs, 4 users 63%user5947301 #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))
56赞 2 revs, 2 users 93%user2100721 #21

请不要像这样粘贴您的控制台输出:

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

还有一件事,如果您使用过某个包中的任何函数,请提及该库。

评论

3赞 BCArg 7/7/2017
您是手动删除并添加,还是有自动方法可以做到这一点?>#
4赞 user2100721 7/22/2017
@BCArg我手动删除。但是,为了添加,我在编辑器中使用快捷方式。>#Ctrl+Shift+CRStudio
0赞 Abednego Nasila 6/14/2023
@user2100721 您可以直接在 Rstudio 编辑器中将 All 替换为。您只需将文本粘贴到编辑器,然后单击编辑器窗格顶部的搜索图标即可。输入搜索输入,在替换输入中单击“全部替换”按钮。>#>#
25赞 dank #22

最好使用包中的函数来显示预期发生的情况。因此,其他人可以更改您的代码,直到它运行没有错误。这减轻了那些愿意帮助你的人的负担,因为这意味着他们不必解码你的文本描述。例如testthat

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

比“我认为 y 等于或超过 10 时 x 会变成 1.23,否则会变成 3.21,但我没有得到任何结果”更清楚。即使在这个愚蠢的例子中,我认为代码比文字更清晰。使用可以让你的帮助者专注于代码,从而节省时间,并为他们提供一种在发布问题之前知道他们已经解决了你的问题的方法testthat

48赞 5 revs, 2 users 84%andrii #23

您可以使用 reprex 执行此操作。

正如 mt1022 所指出的,“......用于生成最小、可重现示例的好包是 Tidyverse“Reprex”。

根据 Tidyverse 的说法:

“reprex”的目标是将你有问题的代码打包,以便其他人可以运行它并感受到你的痛苦。

tidyverse网站上给出了一个例子。

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

我认为这是创建可重现示例的最简单方法

评论

1赞 Diego 8/25/2021
当我使用的函数不是来自基础 R 时,我收到错误,这是意料之中的吗?
3赞 Arthur Yip 8/27/2021
您是否在 Reprex 中加载了库?否则,代码不是独立可重现的
1赞 Dr_Be 11/17/2022
我知道,已经有一段时间了。无论如何,以防万一:在输入和输入之前,您需要将代码复制到剪贴板,因为这是它获取代码的地方。reprex()