如何在data.table上运行apply?

时间:2012-02-10 23:46:22

标签: r apply data.table

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

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列到最后一行执行此操作?类似于上面的那个?

2 个答案:

答案 0 :(得分:32)

在2015-11-24完全重写,修复以前版本中的错误。

您有几个选择。

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

  2. 使用for循环一次一个地运行目标列, 使用set()依次修改每个值。

  3. 使用for循环迭代多个"天真"电话 到[.data.table(),每个修改一列。

  4. 这些方法似乎都同样快,所以你使用哪种方法 主要是品味问题。 (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[, cnames[-1] := lapply(DT1[,cnames[-1],with=FALSE],
                          function(x) gsub(" ", "_", x))]
    })
    ##   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]]))
        }
    })
    ##   user  system elapsed 
    ##  10.65    0.05   10.70 
    
    ## Method 3
    system.time({
        for(cname in cnames[-1]) {
            DT3[ , cname := gsub(" ", "_", DT3[[cname]]), with=FALSE]
        }
    })
    ##   user  system elapsed 
    ##  10.33    0.03   10.37 
    

    有关set():=的详细信息,请阅读他们的帮助页面,点击?set?":="即可获得。

答案 1 :(得分:7)

你可以这样做:

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