Użycie lapply.SD w danych.tabela R
Nie jestem zbyt jasny co do stosowania .SD
i by
.
Na przykład, czy poniższy fragment oznacza: "zmień wszystkie kolumny w DT
na Współczynnik z wyjątkiem A
i B
?"W data.table
Manuale jest też napisane:" .SD
odnosi się do podzbioru data.table
dla każdej grupy (wyłączając kolumny grupujące)" - więc kolumny A
i B
są wykluczone?
DT = DT[ ,lapply(.SD, as.factor), by=.(A,B)]
Jednak czytałem również, że by
oznacza jak 'group by' w SQL, gdy robisz agregację. Na przykład, jeśli chciałbym podsumować (jak colsum
w SQL) na wszystkich kolumnach oprócz A
i B
czy nadal używam czegoś podobnego? Czy w tym przypadku poniższy kod oznacza pobranie sumy i grupowanie według wartości w kolumnach A
i B
? (weź sum i grupę przez {[18] } jak w SQL)
DT[,lapply(.SD,sum),by=.(A,B)]
To jak zrobić proste colsum
na wszystkich kolumnach oprócz A
i B
?
1 answers
Aby zilustrować powyższe komentarze przykładem, weźmy
set.seed(10238)
# A and B are the "id" variables within which the
# "data" variables C and D vary meaningfully
DT = data.table(A = rep(1:3, each = 5), B = rep(1:5, 3),
C = sample(15), D = sample(15))
DT
# A B C D
# 1: 1 1 14 11
# 2: 1 2 3 8
# 3: 1 3 15 1
# 4: 1 4 1 14
# 5: 1 5 5 9
# 6: 2 1 7 13
# 7: 2 2 2 12
# 8: 2 3 8 6
# 9: 2 4 9 15
# 10: 2 5 4 3
# 11: 3 1 6 5
# 12: 3 2 12 10
# 13: 3 3 10 4
# 14: 3 4 13 7
# 15: 3 5 11 2
Porównaj:
#Sum all columns
DT[ , lapply(.SD, sum)]
# A B C D
# 1: 30 45 120 120
#Sum all columns EXCEPT A, grouping BY A
DT[ , lapply(.SD, sum), by = A]
# A B C D
# 1: 1 15 38 43
# 2: 2 15 30 49
# 3: 3 15 52 28
#Sum all columns EXCEPT A
DT[ , lapply(.SD, sum), .SDcols = !"A"]
# B C D
# 1: 45 120 120
#Sum all columns EXCEPT A, grouping BY B
DT[ , lapply(.SD, sum), by = B, .SDcols = !"A"]
# B C D
# 1: 1 27 29
# 2: 2 17 30
# 3: 3 33 11
# 4: 4 23 36
# 5: 5 20 14
Kilka uwag:
- powiedziałeś " robi poniższy fragment... zmień wszystkie kolumny w
DT
..."
Odpowiedź brzmi Nie , a to jest bardzo ważne dla data.table
. Zwracany obiekt to new data.table
, wszystkie kolumny DT
są dokładnie takie, jakie były przed uruchomieniem kodu.
- wspomniałeś chcąc zmienić typy kolumn
Nawiązując ponownie do powyższego punktu, zauważ, że Twój kod (DT[ , lapply(.SD, as.factor)]
) zwraca nowy data.table
i nie zmienia się DT
w ogóle. Jednym (niepoprawnym ) sposobem na to, co robi się z data.frame
S w base
, jest zastąpienie starego data.table
nowym data.table
, które zwróciłeś, tzn. DT = DT[ , lapply(.SD, as.factor)]
.
Jest to marnotrawstwo, ponieważ polega na tworzeniu kopii DT
, które mogą być zabójcą wydajności, gdy DT
jest duża. The correct data.table
podejście do tego problemu polega na aktualizacji kolumn przez odniesienie za pomocą `:=`
, np. DT[ , names(DT) := lapply(.SD, as.factor)]
, co nie tworzy kopii danych. Zobacz też data.table
's reference semantics vignette więcej na ten temat.
- Wspomniałeś o porównaniu wydajności
lapply(.SD, sum)
do wydajności colSums
. sum
jest wewnętrznie zoptymalizowane w data.table
(możesz zauważyć, że jest to prawda z wyniku dodania argumentu verbose = TRUE
wewnątrz []
); aby zobaczyć to w akcji, podkręćmy trochę DT
i uruchom benchmark:
Wyniki:
library(data.table)
set.seed(12039)
nn = 1e7; kk = seq(100L)
DT = as.data.table(replicate(26L, sample(kk, nn, TRUE)))
DT[ , LETTERS[1:2] := .(sample(100L, nn, TRUE), sample(100L, nn, TRUE))]
library(microbenchmark)
microbenchmark(times = 100L,
colsums = colSums(DT[ , !c("A", "B"), with = FALSE]),
lapplys = DT[ , lapply(.SD, sum), .SDcols = !c("A", "B")])
# Unit: milliseconds
# expr min lq mean median uq max neval
# colsums 1624.2622 2020.9064 2028.9546 2034.3191 2049.9902 2140.8962 100
# lapplys 246.5824 250.3753 252.9603 252.1586 254.8297 266.1771 100
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-08-16 05:09:34