为了账号安全,请及时绑定邮箱和手机立即绑定

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

/ 猿问

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

白衣染霜花 2019-05-20 13:30:58

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

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

在另外还有其他招数来使用dput()dump()structure()?你什么时候应该包括library()require()声明?其中保留字应避免一个,此外cdfdata等?

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


查看完整描述

8 回答

?
繁星淼淼


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


重现错误所必需的最小数据集

重现错误所需的最小可运行代码,可以在给定数据集上运行。

有关所使用的软件包,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()或索引。然后用eg。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还是其他任何应用程序),还应该为这些应用程序提供版本号,如果可能,还应提供有关设置的必要信息。


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


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


查看完整回答
反对 回复 2019-05-20
?
慕神8447489

如何编写可重现的示例。

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

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

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

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

    1. dput(mtcars)在R中运行

    2. 复制输出

    3. 在我可重现的脚本中,键入mtcars <-然后粘贴。

  • 花一点时间确保您的代码易于其他人阅读:

    • 确保你已经使用了空格,你的变量名称简洁,但信息丰富

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

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

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

你可以通过启动一个新的R会话并粘贴你的脚本来检查你是否真的做了一个可重现的例子。

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


查看完整回答
反对 回复 2019-05-20
?
慕仰8121524

就个人而言,我更喜欢“一个”衬里。一些事情:


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


查看完整回答
反对 回复 2019-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上工作,输出会自动复制到剪贴板,这样您只需运行它然后粘贴到您的问题。

来源可在此处获得:

例:

# 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问题帖子,也更容易复制+粘贴。

您现在可以指定将占用多少行文本输出(即,您将粘贴到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==


查看完整回答
反对 回复 2019-05-20
?
春华秋衣

这是一个很好的指南:

http://www.r-bloggers.com/three-tips-for-posting-good-questions-to-r-help-and-stack-overflow/

但最重要的是:只要确保你制作了一小段我们可以运行的代码来查看问题所在。对此有用的功能是dput(),但如果您有非常大的数据,您可能想要制作一个小样本数据集或仅使用前10行左右。

编辑:

还要确保您确定问题出在哪里。该示例不应该是整个R脚本,“On line 200存在错误”。如果您使用R(我喜欢browser())和谷歌中的调试工具,您应该能够真正确定问题所在,并重现一个简单的例子,其中同样的事情出错了。


查看完整回答
反对 回复 2019-05-20
?
ibeautiful

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

小字这个词特别重要。您应该瞄准一个可重复性最小的示例,这意味着数据和代码应尽可能简单地解释问题。


查看完整回答
反对 回复 2019-05-20
?
慕丝7291255

从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

") 


查看完整回答
反对 回复 2019-05-20
?
元芳怎么了

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

  • 可能需要将数据发布到某处并提供URL。

  • 如果数据无法向公众发布但可以共享,那么您可以通过电子邮件将其发送给感兴趣的各方(尽管这会减少需要工作的人数)在上面)。

  • 我实际上没有看到这样做,因为无法发布数据的人对于以任何形式发布数据都很敏感,但似乎有理由认为,如果有足够的匿名/加密/损坏数据,人们仍然可以发布数据某种程度上来说。

如果您不能做其中任何一项,那么您可能需要聘请一名顾问来解决您的问题......

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


查看完整回答
反对 回复 2019-05-20

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信