2015-08-16 9 views
6

In answering this question su join mobili con il pacchetto data.table, ho riscontrato comportamenti strani quando si utilizzano più condizioni.Comportamento anomalo quando si uniscono a più condizioni

considerando i seguenti gruppi di dati:

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

quando voglio unire dt con dt_lu dove solo i casi di dt_lu che hanno lo stesso place e dove dt_lu$num è superiore dt$num come segue:

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

Ottengo il risultato desiderato:

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 

Quando voglio aggiungere una condizione aggiuntiva, posso ottenere il risultato desiderato facilmente concatenando che le condizioni supplementari come segue:

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

che mi dà:

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 

Tuttavia quando aggiungo l'ulteriore condizione (cioè la differenza deve essere inferiore 2) come segue:

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] 

non ottengo il risultato atteso:

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 

Inoltre, ricevo il seguente messaggio di avviso:

messaggio di avviso: In [.data.table (dt_lu, dt, la lista (TID = i.t_id, tnum = i.num, fnum = num [numero articolo <: la colonna 3 del risultato per il gruppo 1 è la lunghezza 2 ma la colonna più lunga in questo risultato è 3. Riciclata lasciando il resto di 1 articoli. Questo avviso è una volta solo per il primo gruppo con questo problema.

Il risultato atteso sarebbe:

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 

Ho volutamente mantenuto le rownumbers dal primo esempio per mostrare quali righe devono essere mantenuti nel risultato finale (che è la stessa della soluzione di lavoro) .

Come mostra this answer, dovrebbe essere possibile utilizzare più condizioni all'interno dell'operazione di join.

Ho provato le seguenti alternative, ma entrambi non funzionano:

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] 

Qualcuno mi potrebbe spiegare perché non ottengo il risultato desiderato con più condizioni all'interno della operazione di join?

risposta

8

Il messaggio di avviso emette il problema. Inoltre, usare print() è molto utile qui.

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 

Consideriamo il primo caso in cui la condizione restituisce TRUE, TRUE, FALSE. Ci sono 3 osservazioni per questo gruppo. E la tua j-expression contiene:

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

i.t_id e i.num sono di lunghezza 1 (come vengono da dt). Ma num[..condn..] restituirà lunghezza = 2, mentre f_id restituirà lunghezza = 3. Sia la lunghezza = 1 che la lunghezza = 2 elementi verranno riciclati alla lunghezza dell'elemento/vettore più lungo = 3. Ciò porta a un risultato errato. Poiché 3 non è perfettamente divisibile per 2, restituisce l'avviso.

Cosa avete intenzione di fare è:

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

o equivalentemente:

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

Mettere insieme:

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

Grazie! Se interpreti bene il tuo anwer, sono stato fortunato quando ho usato una sola condizione perché il numero di osservazioni è lo stesso sia per 'fnum' che per' fid'. – Jaap

+0

@Jaap, giusto ... – Arun