2015-08-16 18 views
6

W answering this question o łączeniach tocznych z pakietem data.table, pojawiły się dziwne zachowania przy korzystaniu z wielu warunków.Dziwne zachowanie przy łączeniu z wieloma warunkami

rozważa następujące zbiory danych:

dt <- data.table(t_id = c(1,4,2,3,5), place = c("a","a","d","a","d"), num = c(5.1, 5.1, 6.2, 5.1, 6.2), key=c("place")) 
dt_lu <- data.table(f_id = c(rep(1,4),rep(2,3)), place = c("a","b","c","d","a","d","a"), num = c(6,7,8,9,6,7,8), key=c("place")) 

gdy chcę dołączyć dt z dt_lu gdzie tylko te przypadki dt_lu które mają taką samą place i gdzie dt_lu$num jest wyższa niż dt$num następująco:

dt_lu[dt, list(tid = i.t_id, 
       tnum = i.num, 
       fnum = num[i.num < num], 
       fid = f_id), 
     by = .EACHI] 

Otrzymuję oczekiwany wynik:

place tid tnum fnum fid 
1:  a 1 5.1 6 1 
2:  a 1 5.1 6 2 
3:  a 1 5.1 8 2 
4:  a 4 5.1 6 1 
5:  a 4 5.1 6 2 
6:  a 4 5.1 8 2 
7:  a 3 5.1 6 1 
8:  a 3 5.1 6 2 
9:  a 3 5.1 8 2 
10:  d 2 6.2 9 1 
11:  d 2 6.2 7 2 
12:  d 5 6.2 9 1 
13:  d 5 6.2 7 2 

Gdy chcę dodać dodatkowy warunek, można uzyskać pożądany rezultat łatwo łańcuchowym, że dodatkowe warunki następująco:

dt_lu[dt, list(tid = i.t_id, 
       tnum = i.num, 
       fnum = num[i.num < num], 
       fid = f_id), 
     by = .EACHI][fnum - tnum < 2] 

który daje mi:

place tid tnum fnum fid 
1:  a 1 5.1 6 1 
2:  a 1 5.1 6 2 
3:  a 4 5.1 6 1 
4:  a 4 5.1 6 2 
5:  a 3 5.1 6 1 
6:  a 3 5.1 6 2 
7:  d 2 6.2 7 2 
8:  d 5 6.2 7 2 

Jednak gdy dodaję dodatkowy warunek (tj. różnica musi być mniejsza niż 2) jak następuje:

dt_lu[dt, list(tid = i.t_id, 
       tnum = i.num, 
       fnum = num[i.num < num & num - i.num < 2], 
       fid = f_id), 
     by = .EACHI] 

nie dostać oczekiwanego rezultatu:

place tid tnum fnum fid 
1:  a 1 5.1 6 1 
2:  a 1 5.1 6 2 
3:  a 1 5.1 6 2 
4:  a 4 5.1 6 1 
5:  a 4 5.1 6 2 
6:  a 4 5.1 6 2 
7:  a 3 5.1 6 1 
8:  a 3 5.1 6 2 
9:  a 3 5.1 6 2 
10:  d 2 6.2 7 1 
11:  d 2 6.2 7 2 
12:  d 5 6.2 7 1 
13:  d 5 6.2 7 2 

Ponadto, pojawia się następujący komunikat ostrzegawczy:

komunikat ostrzegawczy: W [.data.table (dt_lu, dt, lista (tid = i.t_id, tnum = i.num, fnum = num [i.num <: Kolumna 3 wyniku dla grupy 1 to długość 2, ale najdłuższa kolumna w tym wyniku to 3. Recykling pozostawiając pozostałość z 1 pozycji. To ostrzeżenie dotyczy tylko pierwszej grupy w tym wydaniu.

Oczekiwany wynik to:

place tid tnum fnum fid 
1:  a 1 5.1 6 1 
2:  a 1 5.1 6 2 
4:  a 4 5.1 6 1 
5:  a 4 5.1 6 2 
7:  a 3 5.1 6 1 
8:  a 3 5.1 6 2 
11:  d 2 6.2 7 2 
13:  d 5 6.2 7 2 

Celowo utrzymuje się rownumbers z pierwszym przykładzie, aby pokazać, które rzędy mają być utrzymywane w końcowego (który jest taki sam jak roztwór roboczy) .

Jak pokazuje this answer, powinno być możliwe stosowanie wielu warunków w operacji łączenia.

Próbowałem następujące alternatywy, ale oboje nie pracują:

dt_lu[dt, list(tid = i.t_id, 
       tnum = i.num, 
       fnum = num[(i.num < num) & (num - i.num < 2)], 
       fid = f_id), 
     by = .EACHI] 

dt_lu[dt, { 
    val = num[(i.num < num) & (num - i.num < 2)]; 
    list(tid = i.t_id, 
     tnum = i.num, 
     fnum = val, 
     fid = f_id)}, 
    by = .EACHI] 

mógłby ktoś wytłumaczyć mi, dlaczego nie dać pożądanego rezultatu z wielu warunków wewnątrz operacji przyłączyć?

Odpowiedz

8

Komunikat ostrzegawczy przekazuje problem. Użyteczne jest tutaj również użycie print().

dt_lu[dt, print(i.num < num & num - i.num < 2), by=.EACHI] 
# [1] TRUE TRUE FALSE 
# [1] TRUE TRUE FALSE 
# [1] TRUE TRUE FALSE 
# [1] FALSE TRUE 
# [1] FALSE TRUE 
# Empty data.table (0 rows) of 3 cols: place,place,num 

Rozważmy pierwszy przypadek, gdy warunek jest TRUE, TRUE, FALSE. Istnieją 3 obserwacje dla tej grupy. A twój j-expression zawiera:

.(tid = i.t_id, 
    tnum = i.num, 
    fnum = num[i.num < num & num - i.num < 2], 
    fid = f_id) 

i.t_id i i.num są o długości 1 (ponieważ pochodzą one z dt). Ale num[..condn..] zwróci długość = 2, natomiast f_id zwróci długość = 3. Zarówno długość = 1, jak i długość = 2 elementy zostaną poddane recyklingowi do długości najdłuższego elementu/wektora = 3. To prowadzi do nieprawidłowego wyniku. Ponieważ 3 nie jest doskonale podzielne przez 2, zwraca ostrzeżenie.

Co zamierza Pan zrobić, to:

.(tid = i.t_id, 
    tnum = i.num, 
    fnum = num[i.num < num & num - i.num < 2], 
    fid = f_id[i.num < num & num - i.num < 2]) 

lub równoważnie:

{ 
    idx = i.num < num & num - i.num < 2 
    .(tid = i.t_id, tnum = i.num, fnum = num[idx], fid = f_id[idx]) 
} 

Wprowadzenie go razem:

dt_lu[dt, 
     { 
     idx = i.num < num & num - i.num < 2 
     .(tid = i.t_id, tnum = i.num, fnum = num[idx], fid = f_id[idx]) 
     }, 
by = .EACHI] 
# place tid tnum fnum fid 
# 1:  a 1 5.1 6 1 
# 2:  a 1 5.1 6 2 
# 3:  a 4 5.1 6 1 
# 4:  a 4 5.1 6 2 
# 5:  a 3 5.1 6 1 
# 6:  a 3 5.1 6 2 
# 7:  d 2 6.2 7 2 
# 8:  d 5 6.2 7 2 
+0

Thanx! Jeśli dobrze zinterpretowałeś twoją anwer, miałem szczęście, gdy użyłem tylko jednego warunku, ponieważ liczba obserwacji jest taka sama dla obu "fnum" i "fid". – Jaap

+0

@Jap, w prawo ... – Arun