2013-05-30 29 views
46

我有一个data.table,我想在某些列上执行相同的操作。这些列的名称在字符向量中给出。在这个特定的例子中,我想将所有这些列乘以-1。如何将相同的功能应用于data.table中的每个指定列

有些玩具的数据和矢量指定相关列:

library(data.table) 
dt <- data.table(a = 1:3, b = 1:3, d = 1:3) 
cols <- c("a", "b") 

现在我做这种方式,遍历的特征向量:

for (col in 1:length(cols)) { 
    dt[ , eval(parse(text = paste0(cols[col], ":=-1*", cols[col])))] 
} 

有没有办法做到这直接没有for循环?

回答

93

这似乎工作:

dt[ , (cols) := lapply(.SD, "*", -1), .SDcols = cols] 

结果是

a b d 
1: -1 -1 1 
2: -2 -2 2 
3: -3 -3 3 

这里有一些技巧:

  • 因为有括号中(cols) :=,结果被分配到cols中指定的列,而不是一些名为“cols”的新变量。
  • .SDcols告诉我们只查看这些列,并允许我们使用D与这些列关联的.SDS ubset。
  • lapply(.SD, ...).SD上运行,它是列的列表(如所有data.frames和data.tables)。 lapply返回一个列表,所以最后j看起来像cols := list(...)

编辑:这里的另一种方式,是可能更快,因为@Arun提到:

for (j in cols) set(dt, j = j, value = -dt[[j]]) 
+12

另一种方法是使用'set'和'for-loop'。我怀疑它会更快。 – Arun

+3

@阿伦我做了一个编辑。这是你的意思吗?我之前没有使用'set'。 – Frank

+0

@弗兰克,非常!它避免了'.SD'的创建。即使对于这个特定的操作,.SD不应该花费太多,因为它不是为每个'by'创建的。但是,我仍然喜欢'设置'这个问题。 – Arun

6

我想补充一个答案,当你想改变的列名好。如果你想计算多列的对数,这在实证工作中经常是这样。

cols <- c("a", "b") 
out_cols = paste("log", cols, sep = ".") 
dt[, c(out_cols) := lapply(.SD, function(x){log(x = x, base = exp(1))}), .SDcols = cols] 
相关问题