Как применить ту же функцию к каждому указанному столбцу в данных.стол
у меня есть сведения.таблица, с которой я хотел бы выполнить ту же операцию на определенные столбцы. Имена этих столбцов задаются в символьном векторе. В этом конкретном примере я хотел бы умножить все эти столбцы на -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])))]
}
есть ли способ сделать это напрямую, без по петля?
3 ответа:
это, кажется, работает:
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
ubset изD
ata, связанные с теми столбцы.lapply(.SD, ...)
работает на.SD
, который представляет собой список столбцов (как и все данные.кадры и данные.таблицы.)lapply
возвращает список, так что в концеj
выглядит так:cols := list(...)
.EDIT: вот еще один способ, который, вероятно, быстрее, как упоминал @Arun:
for (j in cols) set(dt, j = j, value = -dt[[j]])
Я хотел бы добавить ответ, когда вы хотите изменить название столбцов, а также. Это очень удобно, если вы хотите вычислить логарифм нескольких столбцов, что часто бывает в эмпирической работе.
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]
обновление: Ниже приведен аккуратный способ сделать это без цикла for
dt[,(cols):= - dt[,..cols]]
это аккуратный способ для легкой читаемости кода. Но что касается производительности, то она остается за решением Фрэнка в соответствии с приведенным ниже результатом microbenchmark
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
как показано в таблице
Мой Предыдущий Ответ: Следующее также работает
for (j in cols) dt[,(j):= -1 * dt[, ..j]]