2016-05-18 27 views
10

Mam następujący problem, który ma prawdopodobnie całkiem proste rozwiązanie: Gdy używamdata.table GDZIE wcześniej przez

library (data.table) 
actions = data.table(User_id = c("Carl","Carl","Carl","Lisa","Moe"), 
        category = c(1,1,2,2,1), 
        value= c(10,20,30,40,50)) 

    User_id category value 
1: Carl  1 10 
2: Carl  1 20 
3: Carl  2 30 
4: Lisa  2 40 
5:  Moe  1 50 

actions[category==1,sum(value),by= User_id] 

Problem polega na tym, że najwyraźniej to pierwsze sortuje wiersze gdzie kategoria 1 a następnie używa polecenia by. Więc co mam to:

User_id V1 
1: Carl 30 
2:  Moe 50 

Ale co chcę jest:

User_id V1 
1: Carl 30 
2: Lisa 0 
3:  Moe 50 

buduję data.table właśnie zawierający informacje o użytkownikach, tak:

users = actions[,User_id,by= User_id] 
users$value_one = actions[category==1,.(value_one =sum(value)),by= User_id]$value_one 

który zgłasza błędy lub zawiera błędne wartości, gdy niektórzy użytkownicy nie mają żadnych wpisów.

+0

Można użyć 'działań [Sum (ifelse (kategoria == 1, value, 0)), przez = User_id] '. – nrussell

+0

IIUC powiązane z [FR # 788] (https://github.com/Rdatatable/data.table/issues/788) – MichaelChirico

Odpowiedz

11

Jest to prawie tak samo zwięzłe i wykonuje pracę.

actions[, .SD[category==1, sum(value)], by=User_id] 
# User_id V1 
# 1: Carl 30 
# 2: Lisa 0 
# 3:  Moe 50 

## Or, better yet, no need to muck around with .SD, (h.t. David Arenburg) 
actions[, sum(value[category == 1]), by = User_id] 
# User_id V1 
# 1: Carl 30 
# 2: Lisa 0 
# 3:  Moe 50 

Jeżeli względna nieefektywność powyższe jest problemem w przypadku użycia, tutaj jest bardziej wydajna alternatywa:

res <- actions[, .(val=0), by=User_id] 
res[actions[category==1, .(val=sum(value)), by=User_id], val:=i.val, on="User_id"]  
res 
# User_id val 
# 1: Carl 30 
# 2: Lisa 0 
# 3:  Moe 50 
+3

Lub po prostu 'actions [, suma (value [category == 1]), przez = User_id] 'bez zakłócania z' .SD'. Chociaż, mimo że podejścia te wydają się "* prawie tak zwięzłe *", są znacznie mniej wydajne niż to, co OP próbował zrobić, ponieważ filtrujesz według 'category == 1' * przez każdy *' User_id' raczej tylko raz. –

+0

@DavidArenburg Uzgodnione. Miałem podobne obawy, więc dodałem drugą, mniej zwięzłą, ale bardziej wydajną opcję. –

+0

Innym sposobem radzenia sobie z włączaniem niewykorzystanych poziomów byłoby scalenie, takie jak 'actions [category == 1] [users, sum (value, na.rm = TRUE), on =" User_id ", przez = .EACHI]'. Niestety, wygląda na to, że 'suma' nie wyzwala optymalizacji GForce, jeśli na.rm jest zaangażowany. – Frank