为了账号安全,请及时绑定邮箱和手机立即绑定

如何对data.table中的每个指定列应用相同的函数

/ 猿问

如何对data.table中的每个指定列应用相同的函数

慕后森 2019-10-16 13:09:05

如何对data.table中的每个指定列应用相同的函数

我有一个data.table,我想用它对某些列执行相同的操作。这些列的名称是在字符向量中给出的。在这个特殊的例子中,我想把所有这些列乘以-1。

一些玩具数据和指定相关列的向量:

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循环直接执行此操作的方法?


查看完整描述

3 回答

?
烙印99

这似乎是可行的:

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

    告诉调用,我们只查看这些列,并允许我们使用

    .SD

    S

    二值

    D

    与这些列关联的ATA。
  • lapply(.SD, ...)

    .SD

    ,它是列的列表(与所有data.framework和data.table类似)。

    lapply

    返回一个列表,所以最后

    j

    看上去

    cols := list(...).

编辑以下是另一种可能更快的方式,正如@Arun提到的那样:

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



查看完整回答
反对 回复 2019-10-17
?
白板的微信

当您也想更改列的名称时,我想添加一个答案。如果您想要计算多列的对数,这是非常方便的,这通常是经验工作中的情况。

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]


查看完整回答
反对 回复 2019-10-17
?
呼啦一阵风

下面是一种无需for循环即可完成此操作的巧妙方法

dt[,(cols):= - dt[,..cols]]

这是一种简洁的代码可读性方法。但是在性能方面,它仍然落后于Frank的解决方案,根据下面的微基准结果

mbm = microbenchmark(
  base = for (col in 1:length(cols)) {
    dt[ , eval(parse(text = paste0(cols[col], ":=-1*", cols[col])))]
  },
  franks_solution1 = dt[ , (cols) := lapply(.SD, "*", -1), .SDcols = cols],
  franks_solution2 =  for (j in cols) set(dt, j = j, value = -dt[[j]]),
  hannes_solution = dt[, c(out_cols) := lapply(.SD, function(x){log(x = x, base = exp(1))}), .SDcols = cols],
  orhans_solution = for (j in cols) dt[,(j):= -1 * dt[,  ..j]],
  orhans_solution2 = dt[,(cols):= - dt[,..cols]],
  times=1000)mbm

Unit: microseconds
expr                  min        lq      mean    median       uq       max neval
base_solution    3874.048 4184.4070 5205.8782 4452.5090 5127.586 69641.789  1000  franks_solution1  313.846  349.1285  
448.4770  379.8970  447.384  5654.149  1000    franks_solution2 1500.306 1667.6910 2041.6134 1774.3580 1961.229  
9723.070  1000    hannes_solution   326.154  405.5385  561.8263  495.1795  576.000 12432.400  1000orhans_solution 
 3747.690 4008.8175 5029.8333 4299.4840 4933.739 35025.202  1000  orhans_solution2  752.000  831.5900 1061.6974 
  897.6405 1026.872  9913.018  1000


我先前的回答:以下也有效

for (j in cols)
  dt[,(j):= -1 * dt[,  ..j]]



查看完整回答
反对 回复 2019-10-17

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信