34

我将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 列到最后的所有列执行此操作,类似于上述之一?

4

2 回答 2

36

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

还在 2019-09-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()and的更多详细信息:=,请阅读他们的帮助页面,通过键入?setor获得?":="

于 2012-02-11T00:45:17.807 回答
7

你可以这样做:

library("stringr")
dt[, -1] <- lapply(dt[, -1], function(x) str_replace(x," ","_"))
于 2012-02-11T00:21:31.820 回答