【问题标题】:How do I run apply on a data.table?如何在 data.table 上运行 apply?
【发布时间】:2012-03-03 10:24:02
【问题描述】:

我有一个data.table,第 2 到 20 列是带空格的字符串(例如,“物种名称”)。我想同时在所有这些列上运行str_replace(),以便所有“物种名称”都变成“物种名称”。我可以这样做:

data.table(apply(as.data.frame(dt[,2:dim(dt)[2], with=F]), 2, 
                               function(x){ str_replace(x," ","_") }))

或者,如果我将其保留为 data.table 对象,那么我可以一次完成这一列:

dt[,SpeciesName := str_replace(SpeciesName, " ", "_")

如何对所有第 2 列到最后的所有列执行此操作,类似于上述之一?

【问题讨论】:

    标签: r apply data.table


    【解决方案1】:

    于 2015 年 11 月 24 日完全重写,以修复以前版本中的错误。

    还在 2019 年 9 月 27 日添加了更多现代选项

    你有几个选择。

    1. 使用嵌入式调用处理所有目标列 lapply(),使用:= 将修改后的值分配到位。这 依赖于 := 非常方便的支持同时分配到其 LHS 上命名的多个列。

    2. 使用for 循环逐个遍历目标列, 使用set()依次修改每一个的值。

    3. 使用for 循环迭代多个“幼稚”调用 到[.data.table(),每一个都修改一个列。

    这些方法似乎都一样快,所以你使用哪一种 主要是口味问题。 (1) 非常紧凑,并且 富有表现力。这是我最常使用的,虽然你可能会发现 (2) 更容易阅读。因为它们一次处理和修改一个列,所以 (2) 或 (3) 在您的 data.table 非常大以至于您有遇到限制的危险的罕见情况下将具有优势 由 R 会话的可用内存强加。

    library(data.table)
    
    ## Create three identical 1000000-by-20 data.tables
    DT1 <- data.table(1:1e6,
               as.data.table(replicate(1e6, paste(sample(letters, nr, TRUE),
                                                 sample(letters, nr, TRUE)))))
    cnames <- c("ID", paste0("X", 1:19))
    setnames(DT1, cnames)
    DT2 <- copy(DT1); DT3 <- copy(DT1)
    
    ## Method 1
    system.time({
    DT1[, .SDcols=cnames[-1L], cnames[-1L] := 
      lapply(.SD, function(x) gsub(" ", "_", x, fixed=TRUE)), ]
    })
    ##   user  system elapsed 
    ##  10.90    0.11   11.06 
    
    ## Method 2
    system.time({
        for(cname in cnames[-1]) {
            set(DT2, j=cname, value=gsub(" ", "_", DT2[[cname]], fixed=TRUE))
        }
    })
    ##   user  system elapsed 
    ##  10.65    0.05   10.70 
    
    ## Method 3
    system.time({
        for(cname in cnames[-1]) {
            DT3[ , (cname) := gsub(" ", "_", get(cname), fixed=TRUE)]
        }
    })
    ##   user  system elapsed 
    ##  10.33    0.03   10.37 
    

    有关set() 和:= 的更多详细信息,请阅读他们的帮助页面,通过键入?set 或?":=" 获得。

    【讨论】:

    • 这是一个有趣的案例。在这里,20 列中有 19 列正在被替换; := 的 RHS 几乎是所有表格。 := 的优势在例如将一或两列添加到 20 或修改一或两列 20 时更大。在这些情况下,大部分列都保留在原位,:= 比复制整个表要快得多。
    • 另外,set() 是 v1.8.0 中的一个新功能(还没有在 CRAN 上),它直接提供了:= 功能。在循环内分配时,set() 可以比:= 快得多(以便更自然地编程)。主页上的最新新闻中有一个例子。
    • @MatthewDowle -- 感谢您的 cmets。他们提醒我,在周末,我对我在这里给出的答案有一种唠叨的感觉,并促使我重新审视这个问题。显然,我有充分的理由感到被唠叨。请看看我修改后的答案。另外请将您在 cmets 中获得的任何建议添加到我的回答文本中,您认为它们可能会有所帮助。我会看看set(),但还没有资格讨论它。再次感谢您为继续开发 data.table 包所做的所有工作!
    • 啊,那更好 :-) 如果我可以 +2,我会的。在 := 的 RHS 上,也许可以尝试使用 DT1[[cname]] 而不是 DT1[,cname,with=FALSE]。 [[ 不会复制(直到写入),因此在整列提取时应该比 [.data.table 快(未经测试的猜测)。
    • @Hack-R nr=20 解密 cmets
    【解决方案2】:

    你可以这样做:

    library("stringr")
    dt[, -1] <- lapply(dt[, -1], function(x) str_replace(x," ","_"))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-20
      • 2019-06-03
      • 1970-01-01
      • 2022-12-19
      • 1970-01-01
      • 2014-08-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多