2013-05-30 10 views
46

Mam tabelę danych, z którą chciałbym wykonać tę samą operację w niektórych kolumnach. Nazwy tych kolumn podane są w wektorze znakowym. W tym konkretnym przykładzie chciałbym pomnożyć wszystkie te kolumny przez -1.Jak zastosować tę samą funkcję do każdej określonej kolumny w data.table

Niektóre dane zabawki i wektor określający odpowiednie kolumny:

library(data.table) 
dt <- data.table(a = 1:3, b = 1:3, d = 1:3) 
cols <- c("a", "b") 

Teraz robię to w ten sposób, zapętlenie nad wektor znaków:

for (col in 1:length(cols)) { 
    dt[ , eval(parse(text = paste0(cols[col], ":=-1*", cols[col])))] 
} 

Czy istnieje sposób, aby zrobić to bezpośrednio bez pętli for?

Odpowiedz

93

To wydaje się działać:

dt[ , (cols) := lapply(.SD, "*", -1), .SDcols = cols] 

Rezultatem jest

a b d 
1: -1 -1 1 
2: -2 -2 2 
3: -3 -3 3 

Istnieje kilka sztuczek tutaj:

  • Ponieważ istnieje nawiasy w (cols) :=, wynik jest przypisany do kolumn określonych w cols zamiast do nowej zmiennej o nazwie "cols".
  • .SDcols mówi, że patrzymy tylko na te kolumny, i pozwala nam korzystać z .SD, S ubset z ata powiązanego z tymi kolumnami.
  • lapply(.SD, ...) działa na .SD, która jest listą kolumn (jak wszystkie dane.frame i data.tables). lapply zwraca listę, więc w końcu j wygląda jak cols := list(...).

EDIT: Oto kolejny sposób, że jest to prawdopodobnie szybciej, jak wspomniano @Arun:

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

innym sposobem jest użycie 'set' z' for-loop'. Podejrzewam, że będzie szybciej. – Arun

+3

@Arun Dokonałem edycji. Czy to miałeś na myśli? Nie użyłem wcześniej 'set'. – Frank

+0

@Frank, bardzo! Unika tworzenia '.SD'. Mimo że dla tej konkretnej operacji, .SD nie powinno kosztować wiele, ponieważ nie jest tworzone dla każdego 'by'. Ale nadal wolę 'set' na to pytanie. – Arun

6

Chciałbym dodać odpowiedź, jeśli chcesz zmienić nazwę kolumny jak dobrze. Jest to bardzo przydatne, jeśli chcesz obliczyć logarytm z wielu kolumn, co często ma miejsce w pracy empirycznej.

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] 
Powiązane problemy