在数据表中使用dput()时,不要带上.internal.selfref。

4

最近有人通过dput()与我分享了他们的数据表,但出现了一个我之前没有遇到过的错误:

Error: unexpected '<' in: " class = c("data.table", "data.frame"), .internal.selfref = <"

经过一番探索,我发现这是特别涉及到数据表的问题,并且根据这些答案的建议,删除internal.selfref = <pointer: 0x7fd60e036ce0>就可以成功地分配他们的数据。

然而,我预计会在初学者之间频繁共享这些类型的数据;我还没有找到一个合理/可持续的解决方案来防止这个dput导出,只能使用临时函数和/或在运行后删除它。

如果我从dput中的control = c("keepNA", "keepInteger", "niceNames", "showAttributes")中删除showAttributes,那么.internal.selfref就会消失,但结构的其他内容也会消失。

上面链接的问题和答案是5-9年前提供的;我希望可能有一些改进的功能(我显然不知道)可以告诉dput忽略这个问题,或者在dput之前我可以对数据表本身做些什么来完全删除.internal.selfref

有没有办法提供一个data.table对象的dput而不产生.internal.selfref

提前感谢。

问题示例:

dattab <- data.table::data.table(a = 1:5, b = 6:10)
dput(dattab)

structure(list(a = 1:5, b = 6:10), row.names = c(NA, -5L), 
          class = c("data.table", "data.frame"), 
          .internal.selfref = <pointer: 0x7fd60e036ce0>)

将所有属性传递给用户真的很关键吗?如果是这样,可能只需获取自定义 dput 的输出并使用 gsub 或类似工具删除 ".internal.selfref*>"(不是实际的正则表达式代码)部分。 - Carl Witthoft
你考虑过使用saveRDS而不是dput吗?不确定你是如何分享的,但这将创建一个物理副本,可以共享。 - LMc
由于您正在共享数据,我建议在分享之前删除selfref。 - Onyambu
谢谢大家,我想这里需要使用其他方法(即rds)。我考虑过悬赏,但恕我不认为这是同一个问题 - 另一个问题的框架是“如何使用此导入?”,而已接受的解决方案提供了“删除后”方法。由于在我的情况下数据共享将是双向的,因此这更针对问题“如何在没有这个的情况下导出”- 而不仅仅是不计成本地解决问题。生活就是如此 - 如果专家们(你们)这样认为,我们最好研究替代方法! - jpsmith
4个回答

6
将data.table转换为data.frame,然后进行dput。
dput(as.data.frame(dattab))
## structure(list(a = 1:5, b = 6:10), row.names = c(NA, -5L), class = "data.frame")

那么很可能是发帖人或他的目标受众需要编写 newdattab <- as.data.table(dput(as.data.frame(dattab))) - Carl Witthoft

5
有时候我认为与适当的类分享它是很有用的,所以我使用这个函数:
#' dput into a single line
#'
#' @param x object
#' @param assign logical, whether to get the 'x' object's name and
#'   prepend it to the string
#' @param DT logical, whether to remove (and wrap with 'as.data.table')
#'   'internal.selfref' in the dput output
#' @return character length 1, invisibly
#' @export
r2dput <- function(x, assign = TRUE, DT = TRUE) {
  out <- deparse1(x)
  if (isTRUE(DT)) {
    out2 <- gsub(",\\s*\\.internal\\.selfref\\s*=\\s*<pointer:\\s*[0-9a-fx]+>", "", out)
    if (out != out2) {
      out <- paste0("data.table::as.data.table(", out2, ")")
    }
  }
  if (assign) {
    out <- paste(c(as.character(substitute(x)), "<-", out), collapse = " ")
  }
  writeLines(out, con = "clipboard")
  invisible(out)
}

举个例子,

MT <- as.data.table(mtcars[1:3, 11:4])
MT
#     carb  gear    am    vs  qsec    wt  drat    hp
#    <num> <num> <num> <num> <num> <num> <num> <num>
# 1:     4     4     1     0 16.46 2.620  3.90   110
# 2:     4     4     1     0 17.02 2.875  3.90   110
# 3:     1     4     1     1 18.61 2.320  3.85    93

当我想在SO(或与同事)的问题中分享该数据时,我键入r2dput(MT)(因为,你知道,我是r2evans ;-),我只需将其粘贴(Ctrl-V)到评论/问题/答案中,就会得到这个:

MT <- data.table::as.data.table(structure(list(carb = c(4, 4, 1), gear = c(4, 4, 4), am = c(1, 1, 1), vs = c(0, 0, 1), qsec = c(16.46, 17.02, 18.61), wt = c(2.62, 2.875, 2.32), drat = c(3.9, 3.9, 3.85), hp = c(110, 110, 93)), row.names = c(NA, -3L), class = c("data.table", "data.frame")))

这样可以去除不起作用的 指针,同时使用 as.data.table(.) 包装数据,清楚地表明我实际上正在使用的类,并将它们都放在一行上(因为我不喜欢格式化代码块中默认的 dput 方法换行的方式)。

(使用 writeLines(., con="clipboard") 是面向 Windows 的;对于 Linux/MacOS 需要其他机制,我只是还没有使我的代码更具平台通用性。)


1
非常好用的辅助功能。 - undefined
(@DirkEddelbuettel,我有几个这样的辅助函数,用于处理和解决Stack问题,看起来...) - undefined
我很好奇,不过,我刚刚几分钟前更新了代码,我可以问问你为什么要查看这个页面吗?时间上真是巧合啊 @DirkEddelbuettel - undefined
1
当您编辑时,它会重新出现在顶层页面。我看到了这个话题,并查看了问题。您可能知道我的dang包提供了这样的帮助程序。欢迎贡献(在完全归属等情况下,即在DESCRIPTION中将自己添加到贡献者列表)。对于这个,我觉得dtdput可能是一个不错的名字。我会去掉剪贴板的部分。标准输出是可以的。但是如果您想保留粘贴,那也可以。您已经拥有了您需要和想要的帮助程序。 - undefined
我之前确实不知道dang,我会去看一下。(说实话,我特别喜欢剪贴板操作,因为较大的样本数据会造成文本混乱,而且大样本往往会拖慢emacs/ess的速度。所以我只是尽量保持我的控制台“整洁”(以不混乱的方式)。) - undefined
我们每个人都有自己的方式,都很好。我甚至觉得我从来没有用过library(clipr) - undefined

3
考虑使用{constructive}包,对于 Stack Overflow 来说,它几乎总是比dput()更好。它很快将出现在 CRAN 上,但现在您需要安装 GitHub 版本。
# remotes::install_github("cynkra/constructive")
library(constructive)
dattab <- data.table::data.table(a = 1:5, b = 6:10)
MT <- data.table::as.data.table(mtcars[1:3, 11:4])

construct(dattab)
#> data.table::data.table(a = 1:5, b = 6:10)

construct(MT)
#> data.table::data.table(
#>   carb = c(4, 4, 1),
#>   gear = rep(4, 3L),
#>   am = rep(1, 3L),
#>   vs = c(0, 0, 1),
#>   qsec = c(16.46, 17.02, 18.61),
#>   wt = c(2.62, 2.875, 2.32),
#>   drat = c(3.9, 3.9, 3.85),
#>   hp = c(110, 110, 93)
#> )

使用 reprex v2.0.2 在2023年4月29日创建


2
使用attr方法来设置data.table对象的属性。

数据

library(data.table)

dt <- data.table(1:3, 2:4)

dput(dt)
structure(list(V1 = 1:3, V2 = 2:4), row.names = c(NA, -3L), 
class = c("data.table", "data.frame"), 
.internal.selfref = <pointer: 0x55f7f168fef0>)

功能

DTput <- function(x){attr(x, which = ".internal.selfref") <- NULL; dput(x)}

使用

DTput(dt)
structure(list(V1 = 1:3, V2 = 2:4), row.names = c(NA, -3L), 
class = c("data.table", "data.frame"))

1
每次都令人惊叹,@AndreWildberg - 我之前不知道 attr 函数! - jpsmith
1
一如既往令人难以置信的 @AndreWildberg - 不知道 attr 函数! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接