2015-08-16 12 views
6

In answering this question über rollende Joins mit dem data.table-Paket habe ich ein seltsames Verhalten bei der Verwendung mehrerer Bedingungen festgestellt.Ungerades Verhalten beim Verbinden mit mehreren Bedingungen

Betrachtet man die folgenden Datensätze:

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")) 

Als ich dt mit dt_lu anschließen möchten, wo nur diejenigen Fälle von dt_lu, die die gleiche place haben und wo dt_lu$num höher als dt$num wie folgt:

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

Ich bekomme das gewünschte Ergebnis:

Wenn ich möchte eine weitere Bedingung hinzuzufügen, kann ich das gewünschte Ergebnis leicht erhalten, indem, dass zusätzliche Bedingungen Verkettungs wie folgt:

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

das gibt mir:

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 

Allerdings, wenn ich hinzufügen die zusätzliche Bedingung (dh die Differenz muss kleiner als 2 sein) wie folgt:

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] 

Ich habe nicht das erwartete Ergebnis:

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 

Außerdem erhalte ich die folgende Warnmeldung angezeigt:

Nachricht Warnung: In [.data.table (dt_lu, dt, Liste (tid = i.t_id, tnum = i.num, fnum = num [i.num <: Spalte 3 des Ergebnisses für Gruppe 1 ist Länge 2, aber die längste Spalte in diesem Ergebnis ist 3. Recyceltes Verlassen Rest von 1 Artikeln. Diese Warnung gilt nur einmal für die erste Gruppe mit diesem Problem.

Das erwartete Ergebnis wäre:

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 

I die rownumbers von dem ersten Beispiel absichtlich gehalten zu zeigen, welche Zeilen in dem Endergebnis gehalten werden müssen (was das gleiche wie die Arbeitslösung) .

Wie this answer zeigt, sollte es möglich sein, mehrere Bedingungen innerhalb der Join-Operation zu verwenden.

Ich habe versucht, die folgenden Alternativen, aber beide funktionieren nicht:

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] 

mir jemand erklären könnte, warum ich in der Join-Operation nicht das gewünschte Ergebnis mit mehreren Bedingungen erhalten?

Antwort

8

Die Warnmeldung gibt das Problem bekannt. Auch die Verwendung von print() ist hier sehr hilfreich.

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 

Betrachten Sie den ersten Fall, in dem die Bedingung TRUE, TRUE, FALSE auswertet. Es gibt 3 Beobachtungen für diese Gruppe. Und Ihr j-expression enthält:

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

i.t_id und i.num sind die Länge 1 (wie sie kommen aus dt). Aber num[..condn..] wird Länge = 2 zurückgeben, während f_id Länge = 3 zurückgibt. Sowohl die Länge = 1 und Länge = 2 Elemente werden auf die Länge des längsten Element/Vektor = 3 zurückgeführt werden. Das führt zu einem falschen Ergebnis. Da 3 nicht perfekt durch 2 teilbar ist, gibt es die Warnung zurück.

Was beabsichtigen Sie zu tun ist:

.(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]) 

oder äquivalent:

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

Putting es zusammen:

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! Wenn Sie Ihre Antwort gut interpretieren, hatte ich Glück, wenn ich nur eine Bedingung verwende, weil die Anzahl der Beobachtungen für "fnum" und "fid" gleich ist. – Jaap

+0

@Jaap, rechts ... – Arun

Verwandte Themen