Używanie dynamicznych nazw kolumn w ' data.tabela"

Chcę obliczyć średnią każdej z kilku kolumn w danych.tabela, pogrupowana według innej kolumny. Moje pytanie jest podobne do dwóch innych pytań dotyczących SO (Jeden i dwa), ale nie mogłem zastosować ich do mojego problemu.

Oto przykład:

library(data.table)
dtb <- fread(input = "condition,var1,var2,var3
      one,100,1000,10000
      one,101,1001,10001
      one,102,1002,10002
      two,103,1003,10003
      two,104,1004,10004
      two,105,1005,10005
      three,106,1006,10006
      three,107,1007,10007
      three,108,1008,10008
      four,109,1009,10009
      four,110,1010,10010")

dtb
#    condition var1 var2  var3
# 1:       one  100 1000 10000
# 2:       one  101 1001 10001
# 3:       one  102 1002 10002
# 4:       two  103 1003 10003
# 5:       two  104 1004 10004
# 6:       two  105 1005 10005
# 7:     three  106 1006 10006
# 8:     three  107 1007 10007
# 9:     three  108 1008 10008
# 10:     four  109 1009 10009
# 11:     four  110 1010 10010

Obliczenie każdej pojedynczej średniej jest łatwe; np. dla "var1": dtb[ , mean(var1), by = condition]. Ale to szybko staje się kłopotliwe, jeśli istnieje wiele zmiennych i trzeba napisać wszystkie z nich. Tak więc, dtb[, list(mean(var1), mean(var2), mean(var3)), by = condition] jest niepożądane. Potrzebuję kolumny. nazwy żeby były dynamiczne i chciałbym skończyć z czymś takim:

   condition  var1   var2    var3
1:       one 101.0 1001.0 10001.0
2:       two 104.0 1004.0 10004.0
3:     three 107.0 1007.0 10007.0
4:      four 109.5 1009.5 10009.5
Author: Community, 2013-02-18

1 answers

Powinieneś użyć .SDcols (zwłaszcza jeśli masz zbyt wiele kolumn i wymagasz wykonania konkretnej operacji tylko na podzbiorze kolumn (poza zmienną grupującą kolumny).

dtb[, lapply(.SD, mean), by=condition, .SDcols=2:4]

#    condition  var1   var2    var3
# 1:       one 101.0 1001.0 10001.0
# 2:       two 104.0 1004.0 10004.0
# 3:     three 107.0 1007.0 10007.0
# 4:      four 109.5 1009.5 10009.5

Możesz również pobrać wszystkie nazwy kolumn, które chcesz wziąć jako pierwsze w zmiennej, a następnie przekazać je do .SDcols w następujący sposób:

keys <- setdiff(names(dtb), "condition")
# keys = var1, var2, var3
dtb[, lapply(.SD, mean), by=condition, .SDcols=keys]

Edit: jak słusznie zauważył Mateusz Dowle, skoro trzeba obliczyć średnią na każdej innej kolumnie po pogrupowaniu przez condition, można po prostu zrobić:

dtb[, lapply(.SD, mean), by=condition]

David ' s edit: (który został odrzucony): Read more about .SD from this post. Uważam, że jest to istotne. Dzięki @ David.

Edit 2: Załóżmy, że masz data.table ze 1000 wierszami i 301 kolumnami (jedna kolumna do grupowania i 300 kolumn numerycznych):

require(data.table)
set.seed(45)
dt <- data.table(grp = sample(letters[1:15], 1000, replace=T))
m  <- matrix(rnorm(300*1000), ncol=300)
dt <- cbind(dt, m)
setkey(dt, "grp")

I chciałeś znaleźć średnią kolumn, powiedzmy, 251: 300 sam,

  • Możesz obliczyć średnią wszystkich kolumny, a następnie podgrupuj te kolumny (co nie jest zbyt wydajne, jak obliczysz na całych danych).

    dt.out <- dt[, lapply(.SD, mean), by=grp]
    dim(dt.out) # 15 * 301, not efficient.
    
  • Możesz przefiltrować data.table najpierw do tych kolumn, a następnie obliczyć średnią (co ponownie niekoniecznie jest najlepszym rozwiązaniem, ponieważ musisz utworzyć dodatkowy podzbiór danych.tabela za każdym razem, gdy chcesz operacji na określonych kolumnach.

    dt.sub <- dt[, c(1, 251:300), with=FALSE]
    setkey(dt.sub, "grp")
    dt.out <- dt.sub[, lapply(.SD, mean), by=grp]
    
  • Możesz określić każdą z kolumn jeden po drugim, jak zwykle (ale jest to pożądane dla mniejsze dane.tabele)

    # if you just need one or few columns
    dt.out <- dt[, list(m.v251 = mean(V251)), by = grp]
    

Więc jakie jest najlepsze rozwiązanie? Odpowiedź brzmi .SDcols .

Zgodnie z dokumentacją, dla danych.tabela x, .SDcols określa kolumny, które są zawarte w . SD .

To w zasadzie domyślnie filtruje kolumny, które zostaną przekazane do. SD zamiast tworzyć podzbiór (jak to zrobiliśmy wcześniej), tylko jest bardzo wydajne i szybkie!

Jak możemy to zrobić?
  • Określając numery kolumn:

    dt.out <- dt[, lapply(.SD, mean), by=grp, .SDcols = 251:300]
    dim(dt.out) # 15 * 51 (what we expect)
    
  • Lub alternatywnie przez podanie ID kolumny:

    ids <- paste0("V", 251:300) # get column ids
    dt.out <- dt[, lapply(.SD, mean), by=grp, .SDcols = ids]
    dim(dt.out) # 15 * 51 (what we expect)
    

Przyjmuje zarówno nazwy kolumn, jak i liczby jako argumenty. W obu tych przypadkach .SD będzie dostarczane tylko z tymi kolumnami, które określiliśmy.

Mam nadzieję, że to pomoże.
 43
Author: Arun,
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-05-23 12:02:11