Jak zastosować tę samą funkcję do każdej określonej kolumny danych.tabela
Mam dane.tabelę, z którą chciałbym wykonać tę samą operację na niektórych kolumnach. Nazwy tych kolumn są podane w wektorze znaków. W tym konkretnym przykładzie chciałbym pomnożyć wszystkie te kolumny przez -1.
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ętlając wektor znaków:
for (col in 1:length(cols)) {
dt[ , eval(parse(text = paste0(cols[col], ":=-1*", cols[col])))]
}
Czy istnieje sposób, aby to zrobić bezpośrednio bez pętli for?
3 answers
To chyba działa:
dt[ , (cols) := lapply(.SD, "*", -1), .SDcols = cols]
Wynik jest
a b d
1: -1 -1 1
2: -2 -2 2
3: -3 -3 3
Jest tu kilka sztuczek:
- ponieważ w
(cols) :=
są nawiasy, wynik jest przypisywany do kolumn określonych wcols
, zamiast do jakiejś nowej zmiennej o nazwie "cols". -
.SDcols
mówi wywołaniu, że patrzymy tylko na te kolumny, i pozwala nam używać.SD
, zestawuS
zD
ata związanego z tymi kolumnami. -
lapply(.SD, ...)
działa na.SD
, która jest listą kolumny (jak wszystkie dane.ramki i dane.stoły).lapply
zwraca listę, więc na końcuj
wygląda jakcols := list(...)
.
EDIT : oto inny sposób, który jest prawdopodobnie szybszy, jak wspomniał @Arun:
for (j in cols) set(dt, j = j, value = -dt[[j]])
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-02 09:20:16
Chciałbym dodać odpowiedź, Kiedy chcesz zmienić nazwę kolumn, jak również. Jest to bardzo przydatne, jeśli chcesz obliczyć logarytm 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]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-30 08:16:21
UPDATE: Following is a neat way to do it without for loop
dt[,(cols):= - dt[,..cols]]
Jest to zgrabny sposób na łatwą czytelność kodu. Ale jeśli chodzi o wydajność, pozostaje za rozwiązaniem Franka zgodnie z poniższym wynikiem 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
Jak pokazano na poniższym wykresie
Moja Poprzednia Odpowiedź: Następujące również działa
for (j in cols)
dt[,(j):= -1 * dt[, ..j]]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-04 10:48:15