Ho un data.table con cui mi piacerebbe eseguire la stessa operazione su determinate colonne. I nomi di queste colonne sono indicati in un vettore di caratteri. In questo particolare esempio, mi piacerebbe moltiplicare tutte queste colonne di -1.
Alcuni dati giocattolo e un vettore che specificano le colonne pertinenti:
library(data.table) dt <- data.table(a = 1:3, b = 1:3, d = 1:3) cols <- c("a", "b")
In questo momento lo sto facendo in questo modo, scorrendo sul vettore dei personaggi:
for (col in 1:length(cols)) { dt[ , eval(parse(text = paste0(cols[col], ":=-1*", cols[col])))] }
C’è un modo per farlo direttamente senza il ciclo for?
Questo sembra funzionare:
dt[ , (cols) := lapply(.SD, "*", -1), .SDcols = cols]
Il risultato è
abd 1: -1 -1 1 2: -2 -2 2 3: -3 -3 3
Ci sono alcuni trucchi qui:
(cols) :=
, il risultato è assegnato alle colonne specificate in cols
, invece di qualche nuova variabile denominata “cols”. .SDcols
dice alla chiamata che stiamo guardando solo quelle colonne, e ci permette di usare .SD
, l’ubset della D
ata associato a quelle colonne. lapply(.SD, ...)
opera su .SD
, che è una lista di colonne (come tutti i data.frames e data.tables). lapply
restituisce una lista, quindi alla fine j
assomiglia a cols := list(...)
. EDIT : Ecco un altro modo probabilmente più veloce, come menzionato da @Arun:
for (j in cols) set(dt, j = j, value = -dt[[j]])
Vorrei aggiungere una risposta, quando vorresti cambiare anche il nome delle colonne. Ciò risulta abbastanza utile se si desidera calcolare il logaritmo di più colonne, il che è spesso il caso nel lavoro empirico.
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]
AGGIORNAMENTO: Di seguito è un modo pulito per farlo senza ciclo
dt[,(cols):= - dt[,..cols]]
È un modo pulito per una facile leggibilità del codice. Ma per quanto riguarda le prestazioni rimane dietro la soluzione di Frank secondo il risultato del 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
come mostrato nel grafico sottostante
La mia risposta precedente: Il seguente funziona anche
for (j in cols) dt[,(j):= -1 * dt[, ..j]]