Aplicar una función a cada columna especificada en una tabla de datos y actualizarla por referencia
Tengo una tabla de datos con la que me gustaría realizar la misma operación en determinadas columnas. Los nombres de estas columnas se dan en un vector de caracteres. En este ejemplo particular, me gustaría multiplicar todas estas columnas por -1.
Algunos datos de juguetes y un vector que especifica columnas relevantes:
library(data.table)
dt <- data.table(a = 1:3, b = 1:3, d = 1:3)
cols <- c("a", "b")
Ahora mismo lo estoy haciendo de esta manera, recorriendo el vector de caracteres:
for (col in 1:length(cols)) {
dt[ , eval(parse(text = paste0(cols[col], ":=-1*", cols[col])))]
}
¿Hay alguna manera de hacer esto directamente sin el bucle for?
Esto parece funcionar:
dt[ , (cols) := lapply(.SD, "*", -1), .SDcols = cols]
El resultado es
a b d
1: -1 -1 1
2: -2 -2 2
3: -3 -3 3
Aquí hay algunos trucos:
- Debido a que hay paréntesis en
(cols) :=
, el resultado se asigna a las columnas especificadas encols
, en lugar de a alguna nueva variable denominada "cols". .SDcols
le dice a la llamada que solo estamos viendo esas columnas y nos permite usar.SD
, elS
ubset de losD
datos asociados con esas columnas.lapply(.SD, ...)
opera en.SD
, que es una lista de columnas (como todos los marcos de datos y tablas de datos).lapply
devuelve una lista, por lo que al finalj
parececols := list(...)
.
EDITAR : Aquí hay otra forma que probablemente sea más rápida, como mencionó @Arun:
for (j in cols) set(dt, j = j, value = -dt[[j]])
Me gustaría agregar una respuesta cuando desee cambiar también el nombre de las columnas. Esto resulta bastante útil si desea calcular el logaritmo de varias columnas, lo que suele ser el caso en el trabajo empírico.
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]