Zastosuj funkcję na podzbiorze kolumn (.SDcols) podczas stosowania innej funkcji na innej kolumnie (w grupach)
Jest to bardzo podobne do pytania stosującego wspólną funkcję do wielu kolumn data.table
uning .SDcols
odpowiedzi dokładnie tutaj .
Różnica polega na tym, że chciałbym jednocześnie zastosować inną funkcję na innej kolumnie, która nie jest częścią podzbioru .SD
. Poniżej zamieszczam prosty przykład, aby pokazać moją próbę rozwiązania problemu:
dt = data.table(grp = sample(letters[1:3],100, replace = TRUE),
v1 = rnorm(100),
v2 = rnorm(100),
v3 = rnorm(100))
sd.cols = c("v2", "v3")
dt.out = dt[, list(v1 = sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]
Daje następujący błąd:
Error in `[.data.table`(dt, , list(v1 = sum(v1), lapply(.SD, mean)), by = grp,
: object 'v1' not found
Teraz to ma sens, ponieważ v1
kolumna nie jest zawarte w podzbiorze kolumn, które muszą być ocenione jako pierwsze. Więc zbadałem dalej, włączając go do mojego podzbioru kolumn:
sd.cols = c("v1","v2", "v3")
dt.out = dt[, list(sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]
Teraz to nie powoduje błędu, ale dostarcza odpowiedź zawierającą 9 wierszy (dla 3 grup), z sumą powtórzoną trzykrotnie w kolumnie V1
, a środki dla wszystkich 3 kolumn (zgodnie z oczekiwaniami, ale nie chcą) umieszczone w V2
Jak pokazano poniżej:
> dt.out
grp V1 V2
1: c -1.070608 -0.0486639841313638
2: c -1.070608 -0.178154270921521
3: c -1.070608 -0.137625003604012
4: b -2.782252 -0.0794929150464099
5: b -2.782252 -0.149529237116445
6: b -2.782252 0.199925178109264
7: a 6.091355 0.141659419355985
8: a 6.091355 -0.0272192037753071
9: a 6.091355 0.00815760216214876
Rozwiązanie obejścia problemu w 2 krokach
Oczywiście można rozwiązać problem w wielu krokach, obliczając mean
według grupy dla podzbioru kolumn i łącząc go z sum
według grupy dla pojedynczej kolumny w następujący sposób:
dt.out1 = dt[, sum(v1), by = grp]
dt.out2 = dt[, lapply(.SD,mean), by = grp, .SDcols = sd.cols]
dt.out = merge(dt.out1, dt.out2, by = "grp")
> dt.out
grp V1 v2 v3
1: a 6.091355 -0.0272192 0.008157602
2: b -2.782252 -0.1495292 0.199925178
3: c -1.070608 -0.1781543 -0.137625004
Jestem pewien, że to dość prosta rzecz, której mi brakuje, z góry dzięki za wszelkie wskazówki.
2 answers
Update: Issue #495 jest teraz rozwiązany za pomocą tego ostatniego commita , możemy teraz zrobić to dobrze:
require(data.table) # v1.9.7+
set.seed(1L)
dt = data.table(grp = sample(letters[1:3],100, replace = TRUE),
v1 = rnorm(100),
v2 = rnorm(100),
v3 = rnorm(100))
sd.cols = c("v2", "v3")
dt.out = dt[, list(v1 = sum(v1), lapply(.SD,mean)), by = grp, .SDcols = sd.cols]
Należy jednak pamiętać, że w tym przypadku v2
zostanie zwrócona jako lista. To dlatego, że robisz list(val, list())
skutecznie. To, co zamierzasz zrobić, to być może:
dt[, c(list(v1=sum(v1)), lapply(.SD, mean)), by=grp, .SDcols = sd.cols]
# grp v1 v2 v3
# 1: a -6.440273 0.16993940 0.2173324
# 2: b 4.304350 -0.02553813 0.3381612
# 3: c 0.377974 -0.03828672 -0.2489067
Zobacz historię dla starszej odpowiedzi.
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-03-07 23:57:52
Spróbuj tego:
dt[,list(sum(v1), mean(v2), mean(v3)), by=grp]
W data.table
, użycie list()
w drugim argumencie pozwala opisać zestaw kolumn, które prowadzą do ostatecznego data.table
.
Jeśli to coś warte, .SD
może być dość powolne [^1], więc możesz chcieć tego uniknąć, chyba że naprawdę potrzebujesz wszystkich danych dostarczonych w podzbiorze data.table
, Jak możesz dla bardziej wyrafinowanej funkcji.
Inną opcją, jeśli masz wiele kolumn dla .SDcols
, byłoby wykonanie scalenia w jednej linii za pomocą data.table
merge składnia.
Na przykład:
dt[, sum(v1), by=grp][dt[,lapply(.SD,mean), by=grp, .SDcols=sd.cols]]
Aby użyć merge
z data.table
, Musisz najpierw użyć setkey()
na swoim data.table
, aby wiedział, jak dopasować rzeczy.
Tak naprawdę, najpierw trzeba:
setkey(dt, grp)
Następnie możesz użyć powyższej linii, aby uzyskać równoważny wynik.
[^1]: uważam to za szczególnie prawdziwe, ponieważ liczba grup zbliża się do liczby całkowitych wierszy. Może się to zdarzyć na przykład wtedy, gdy kluczem jest indywidualny identyfikator i wiele osób mieć tylko jedną lub dwie obserwacje.
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
2013-12-08 23:12:22