【问题标题】:data.table version of tidyr::unitetidyr::unite 的 data.table 版本
【发布时间】:2016-09-29 10:16:08
【问题描述】:

我需要在我巨大的data.table 中用分隔符合并几列。所以我使用来自tidyr 包的unite

你知道有没有data.table为此优化过的版本吗?

library(data.table)
data <- data.table(id=1:10, col1=11:20, col2=21:30, col3=31:40)
print(data)

library(tidyr)
data <- unite(data, "col_test", col1, col2, col3)
print(data)

【问题讨论】:

    标签: r data.table tidyr


    【解决方案1】:

    我们可以使用do.callpaste

    data[, .(id, col_test=do.call(paste, c(.SD, sep="_"))), .SDcols= col1:col3]
    #     id col_test
    # 1:  1 11_21_31
    # 2:  2 12_22_32
    # 3:  3 13_23_33
    # 4:  4 14_24_34
    # 5:  5 15_25_35
    # 6:  6 16_26_36
    # 7:  7 17_27_37
    # 8:  8 18_28_38
    # 9:  9 19_29_39
    #10: 10 20_30_40
    

    基准测试

    microbenchmark(
      tidyr_unite = {
        unite(data1, "col_test", col1, col2, col3)
      },
      dt_docallPaste = {
        data1[, .(id = data1[["id"]], col_test = do.call(paste, c(.SD, sep="_"))),
             .SDcols= col1:col3]
      },
      apply_Paste = {
        cbind.data.frame(id = data1$id,
                         col_test = apply(data1[, -1, with = FALSE], 1,
                                          paste, collapse = "_"))
      },
      times = 10
    )
    
    # Unit: seconds
    #            expr       min        lq      mean    median        uq       max neval cld
    #     tidyr_unite  7.501491  7.521328  7.720600  7.647506  7.756273  8.219710    10  a 
    #  dt_docallPaste  7.530711  7.558436  7.910604  7.618165  8.429796  8.497932    10  a 
    #     apply_Paste 44.743782 45.797092 46.791288 46.325188 47.330887 51.155663    10   b
    

    与基本apply 相比,tidyrdata.table 版本似乎同样有效。这是意料之中的,因为unite 只是do.call("paste", ...) 的包装器

    source code可以看到:

    unite_.data.frame <- function(data, col, from, sep = "_", remove = TRUE) {
      united <- do.call("paste", c(data[from], list(sep = sep)))
    
      first_col <- which(names(data) %in% from)[1]
    
      data2 <- data
      if (remove) {
        data2 <- data2[setdiff(names(data2), from)]
      }
    
      append_col(data2, united, col, after = first_col - 1)
    }
    

    【讨论】:

    • data.table 解决方案给出错误:Error in eval(expr, envir, enclos) : object 'id' not found.
    • @zx8754 试试data[, .(id=data[["id"]], col_test=do.call(paste, c(.SD, sep="_"))), .SDcols= col1:col3] 因为我使用的是devel版本,所以显示错误。
    • 是的,我的 data.table 版本是 1.9.6,与基本应用相比,添加了基准,希望您不介意。
    • 这是意料之中的。 unite() 只是 do.call("paste", ...) 的包装 - 如果你愿意,我可以编辑你的答案以添加一些解释。而且我认为我们应该在最终答案中只保留一个基准
    • @StevenBeaupré 随意编辑它。感谢 cmets。
    猜你喜欢
    • 2016-06-30
    • 1970-01-01
    • 2019-03-13
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    • 2017-09-14
    • 2018-04-16
    相关资源
    最近更新 更多