Dea*_*gor 70 r data.table
我有一个data.table,我希望在某些列上执行相同的操作.这些列的名称以字符向量给出.在这个特定的例子中,我想将所有这些列乘以-1.
一些玩具数据和指定相关列的向量:
library(data.table)
dt <- data.table(a = 1:3, b = 1:3, d = 1:3)
cols <- c("a", "b")
Run Code Online (Sandbox Code Playgroud)
现在我这样做,循环遍历字符向量:
for (col in 1:length(cols)) {
dt[ , eval(parse(text = paste0(cols[col], ":=-1*", cols[col])))]
}
Run Code Online (Sandbox Code Playgroud)
有没有办法在没有for循环的情况下直接执行此操作?
Fra*_*ank 127
这似乎有效:
dt[ , (cols) := lapply(.SD, "*", -1), .SDcols = cols]
Run Code Online (Sandbox Code Playgroud)
结果是
a b d
1: -1 -1 1
2: -2 -2 2
3: -3 -3 3
Run Code Online (Sandbox Code Playgroud)
这里有一些技巧:
(cols) :=,结果将分配给指定的列cols,而不是名为"cols"的新变量..SDcols告诉我们我们只关注那些列,并允许我们使用与这些列关联的ata .SD的Subset D.lapply(.SD, ...)操作.SD,列表是列(如所有data.frames和data.tables).lapply返回一个列表,所以最后j看起来像cols := list(...).编辑:这是另一种可能更快的方式,正如@Arun提到的:
for (j in cols) set(dt, j = j, value = -dt[[j]])
Run Code Online (Sandbox Code Playgroud)
han*_*101 13
当您想要更改列的名称时,我想添加一个答案.如果您想计算多列的对数,这非常方便,这在经验工作中通常就是这种情况.
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]
Run Code Online (Sandbox Code Playgroud)
更新:以下是一个简洁的方法,无需循环
dt[,(cols):= - dt[,..cols]]
Run Code Online (Sandbox Code Playgroud)
这是一种简单的代码可读性方法.但就性能而言,根据以下微基准测试结果,它仍然落后于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 1000
orhans_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
Run Code Online (Sandbox Code Playgroud)
如下图所示
我以前的答案:以下内容也有效
for (j in cols)
dt[,(j):= -1 * dt[, ..j]]
Run Code Online (Sandbox Code Playgroud)