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?

Author: MichaelChirico, 2015-08-28

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.frameS 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
 42
Author: MichaelChirico,
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