协慌网

登录 贡献 社区

如何制作一个很好的 R 可重复的例子

在与同事讨论性能,教学,发送错误报告或在邮件列表上搜索指导时,以及在 Stack Overflow 上,通常会询问可重现的示例并始终提供帮助。

您有什么建议创建优秀示例的提示?如何以文本格式粘贴中的数据结构?您应该包括哪些其他信息?

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

怎样才能成为一位伟大的重复的例子?

答案

可重复性最小的示例包含以下项目:

  • 重现错误所必需的最小数据集
  • 重现错误所需的最小可运行代码,可以在给定的数据集上运行。
  • 有关所使用的软件包,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.factoras.Dateas.xts ,... 这些与向量和 / 或数据框技巧相结合。

复制您的数据

如果你有一些使用这些技巧难以构建的数据,那么你总是可以使用例如head()subset()或索引来创建原始数据的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对象或来自dplyr分组tbl_df (class grouped_df )。在这些情况下,您可以在共享之前转换回常规数据框, dput(as.data.frame(my_data))

在最坏的情况下,您可以使用read.tabletext参数提供可以读取的文本表示:

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)

生成最少的代码

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

  • 添加所有类型的数据转换。确保提供的数据格式正确(除非这是问题)
  • 复制粘贴一个产生错误的整个函数 / 代码块。首先,尝试找出确切导致错误的行。通常情况下,你会发现自己的问题是什么。

你应该做的是:

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

提供额外信息

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

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

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

(这是我的建议, 如何编写一个可重复的例子 。我试图让它变短但很甜)

如何编写可重现的示例。

如果您提供可重现的示例,您最有可能获得 R 问题的良好帮助。一个可重现的示例允许其他人通过复制和粘贴 R 代码来重新创建您的问题。

为了使您的示例可重现,您需要包含四件事:所需的包,数据,代码和 R 环境的描述。

  • 应该在脚本的顶部加载 ,因此很容易看出示例需要哪些包。

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

    1. 在 R 中运行dput(mtcars)
    2. 复制输出
    3. 在我可重现的脚本中,键入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")