【问题标题】:Cannot use dput for data.table in R不能将 dput 用于 R 中的 data.table
【发布时间】:2014-08-27 17:20:21
【问题描述】:

我有以下 data.table 我不能使用 dput 命令的输出来重新创建它:

> ddt
   Unit Anything index new
1:    A      3.4     1   1
2:    A      6.9     2   1
3:   A1      1.1     1   2
4:   A1      2.2     2   2
5:    B      2.0     1   3
6:    B      3.0     2   3
> 
> 
> str(ddt)
Classes ‘data.table’ and 'data.frame':  6 obs. of  4 variables:
 $ Unit    : Factor w/ 3 levels "A","A1","B": 1 1 2 2 3 3
 $ Anything: num  3.4 6.9 1.1 2.2 2 3
 $ index   : num  1 2 1 2 1 2
 $ new     : int  1 1 2 2 3 3
 - attr(*, ".internal.selfref")=<externalptr> 
 - attr(*, "sorted")= chr  "Unit" "Anything"
> 
> 
> dput(ddt)
structure(list(Unit = structure(c(1L, 1L, 2L, 2L, 3L, 3L), .Label = c("A", 
"A1", "B"), class = "factor"), Anything = c(3.4, 6.9, 1.1, 2.2, 
2, 3), index = c(1, 2, 1, 2, 1, 2), new = c(1L, 1L, 2L, 2L, 3L, 
3L)), .Names = c("Unit", "Anything", "index", "new"), row.names = c(NA, 
-6L), class = c("data.table", "data.frame"), .internal.selfref = <pointer: 0x8948f68>, sorted = c("Unit", 
"Anything"))
> 

粘贴时出现以下错误:

> dt = structure(list(Unit = structure(c(1L, 1L, 2L, 2L, 3L, 3L), .Label = c("A", 
+ "A1", "B"), class = "factor"), Anything = c(3.4, 6.9, 1.1, 2.2, 
+ 2, 3), index = c(1, 2, 1, 2, 1, 2), new = c(1L, 1L, 2L, 2L, 3L, 
+ 3L)), .Names = c("Unit", "Anything", "index", "new"), row.names = c(NA, 
+ -6L), class = c("data.table", "data.frame"), .internal.selfref = <pointer: 0x8948f68>, sorted = c("Unit", 
Error: unexpected '<' in:
"3L)), .Names = c("Unit", "Anything", "index", "new"), row.names = c(NA, 
-6L), class = c("data.table", "data.frame"), .internal.selfref = <"
> "Anything"))
Error: unexpected ')' in ""Anything")"

问题出在哪里,如何解决?感谢您的帮助。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    问题在于dput 打印出外部指针地址(这是data.table 在内部使用的东西,需要时会重新构建),而您并不能真正使用。

    如果您手动删除.internal.selfref 部分,它会工作得很好,除了data.table 对某些操作的一次性投诉。

    您可以为此向data.table 添加 FR,但这需要修改 data.table 的基本函数,类似于当前处理 rbind 的方式。

    【讨论】:

    • 我遇到了同样的问题,我所做的只是将我的因子列转换为字符,它工作正常。
    【解决方案2】:

    我也发现这种行为很烦人。所以我创建了自己的dput 函数,它忽略了.internal.selfref 属性。

    dput <- function (x, file = "", control = c("keepNA", "keepInteger", 
                                        "showAttributes")) 
    {
      if (is.character(file)) 
        if (nzchar(file)) {
          file <- file(file, "wt")
          on.exit(close(file))
        }
      else file <- stdout()
      opts <- .deparseOpts(control)
      # adding these three lines for data.tables
      if (is.data.table(x)) {
        setattr(x, '.internal.selfref', NULL)
      }
      if (isS4(x)) {
        clx <- class(x)
        cat("new(\"", clx, "\"\n", file = file, sep = "")
        for (n in .slotNames(clx)) {
          cat("    ,", n, "= ", file = file)
          dput(slot(x, n), file = file, control = control)
        }
        cat(")\n", file = file)
        invisible()
      }
      else .Internal(dput(x, file, opts))
    }
    

    【讨论】:

    • 感谢您的回答。您确定它不会影响所有其他对象的 dput 输出吗?始终可以将此函数重命名为 dputdt 以仅用于 data.table 对象。
    • 为什么这么复杂?不是简单的dput = function(x, ...) { if(is.data.table(x)) { setattr(x, '.internal.selfref', NULL) }; base::dput(x, ...) } 工作吗?或者更好的是,将is.data.table 替换为inherits
    【解决方案3】:

    如果您已经dput 文件并且在dget 之前不想手动编辑,您可以使用以下方法

    data.table.parse<-function (file = "", n = NULL, text = NULL, prompt = "?", keep.source = getOption("keep.source"), 
                                srcfile = NULL, encoding = "unknown") 
    {
      keep.source <- isTRUE(keep.source)
      if (!is.null(text)) {
        if (length(text) == 0L) 
          return(expression())
        if (missing(srcfile)) {
          srcfile <- "<text>"
          if (keep.source) 
            srcfile <- srcfilecopy(srcfile, text)
        }
        file <- stdin()
      }
      else {
        if (is.character(file)) {
          if (file == "") {
            file <- stdin()
            if (missing(srcfile)) 
              srcfile <- "<stdin>"
          }
          else {
            filename <- file
            file <- file(filename, "r")
            if (missing(srcfile)) 
              srcfile <- filename
            if (keep.source) {
              text <- readLines(file, warn = FALSE)
              if (!length(text)) 
                text <- ""
              close(file)
              file <- stdin()
              srcfile <- srcfilecopy(filename, text, file.mtime(filename), 
                                     isFile = TRUE)
            }
            else {
              text <- readLines(file, warn = FALSE)
              if (!length(text)) {
                text <- ""
              } else {
                text <- gsub("(, .internal.selfref = <pointer: 0x[0-9A-Fa-f]+>)","",text,perl=TRUE)
              }
              on.exit(close(file))
            }
          }
        }
      }
      #  text <- gsub("(, .internal.selfref = <pointer: 0x[0-9A-F]+>)","",text)
      .Internal(parse(file, n, text, prompt, srcfile, encoding))
    }
    data.table.get <- function(file, keep.source = FALSE)
      eval(data.table.parse(file = file, keep.source = keep.source))
    dtget <- data.table.get
    

    然后将您的电话dget 更改为dtget。请注意,由于内联解析,这将使dtgetdget 慢,因此仅在您可以检索data.table 类型的对象的情况下使用它。

    【讨论】:

      猜你喜欢
      • 2013-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-07
      • 1970-01-01
      • 1970-01-01
      • 2018-10-16
      • 1970-01-01
      相关资源
      最近更新 更多