Rolling join na danych.tabela z duplikatami kluczy

Próbuję zrozumieć rolling joins w data.table. Dane do odtworzenia tego podano na końcu.

Podane dane."tabela transakcji w porcie lotniczym w danym czasie": {]}

> dt
   t_id airport thisTime
1:    1       a      5.1
2:    3       a      5.1
3:    2       a      6.2  

(Uwaga t_ids 1 i 3 mają to samo lotnisko i czas)

I tabela przelotu z lotnisk:

> dt_lookup
   f_id airport thisTime
1:    1       a        6
2:    2       a        6
3:    1       b        7
4:    1       c        8
5:    2       d        7
6:    1       d        9
7:    2       e        8

> tables()
     NAME      NROW NCOL MB COLS                  KEY             
[1,] dt           3    3  1 t_id,airport,thisTime airport,thisTime
[2,] dt_lookup    7    3  1 f_id,airport,thisTime airport,thisTime

Chciałbym dopasować wszystkie transakcje do wszystkich następnych możliwych lotów odlatujących z tego lotniska, aby dać:

   t_id airport thisTime f_id
      1       a        6    1
      1       a        6    2
      3       a        6    1
      3       a        6    2

Więc pomyślałem, że to praca:

> dt[dt_lookup, nomatch=0,roll=Inf]
   t_id airport thisTime f_id
1:    3       a        6    1
2:    3       a        6    2

Ale nie zwrócił transakcji t_id == 1.

Z dokumentacji jest napisane:

Zazwyczaj nie powinno być duplikatów w kluczu x,...

Jednak mam duplikaty w moim 'x key' (mianowicie airport & thisTime), i nie do końca widzę/rozumiem, co się dzieje, co oznacza t_id = 1 zostaje usunięte z wyjścia.

Czy ktoś może rzucić trochę światła na to, dlaczego t_id = 1 nie jest zwracany, i jak Mogę dostać join do pracy dla kiedy mam duplikaty?

Dane

library(data.table)
dt <- data.table(t_id = seq(1:3),
                 airport = c("a","a","a"),
                 thisTime = c(5.1,6.2, 5.1), key=c( "airport","thisTime"))

dt_lookup <- data.table(f_id = c(rep(1,4),rep(2,3)),
                        airport = c("a","b","c","d",
                                 "a","d","e"),
                        thisTime = c(6,7,8,9,
                                 6,7,8), key=c("airport","thisTime"))
Author: Jaap, 2015-08-14

1 answers

Powodem, dla którego t_id = 1 nie pojawia się na wyjściu, jest to, że połączenie toczne zajmuje wiersz, w którym kombinacja klawiszy występuje jako ostatnia. Z dokumentacji (podkreślenie moje):

Odnosi się do ostatniej kolumny join, zazwyczaj jest to data, ale może być dowolna uporządkowane zmienne, nieregularne i zawierające luki. If roll = TRUE, a i ' S wiersz pasuje do wszystkich poza ostatnią kolumną x join, a jego wartość w ostatnio dołączam kolumnę spada w lukę (również po ostatnim obserwacja W x dla tego Grupa), wtedy Dominująca wartość w x jest / align = "left" / Operacja ta jest szczególnie szybka przy użyciu zmodyfikowanego wyszukiwanie binarne. operacja znana jest również jako ostatnia obserwacja forward (LOCF).

Rozważmy nieco większe zbiory danych:]}
> DT
   t_id airport thisTime
1:    1       a      5.1
2:    4       a      5.1
3:    3       a      5.1
4:    2       d      6.2
5:    5       d      6.2
> DT_LU
   f_id airport thisTime
1:    1       a        6
2:    2       a        6
3:    2       a        8
4:    1       b        7
5:    1       c        8
6:    2       d        7
7:    1       d        9

Kiedy wykonujesz Rolling join tak jak w twoim pytaniu:

DT[DT_LU, nomatch=0, roll=Inf]

Otrzymujesz:

   t_id airport thisTime f_id
1:    3       a        6    1
2:    3       a        6    2
3:    3       a        8    2
4:    5       d        7    2
5:    5       d        9    1

Jak widać, zarówno z kombinacji klawiszy a, 5.1 jak i d, 6.2 ostatni wiersz jest używany do / align= "left" / Ponieważ używasz Inf jako wartości roll, wszystkie przyszłe wartości są włączone do wynikowego datatable. Kiedy używasz:

DT[DT_LU, nomatch=0, roll=1]

Widzisz, że zawiera się tylko pierwsza wartość w przyszłości:

   t_id airport thisTime f_id
1:    3       a        6    1
2:    3       a        6    2
3:    5       d        7    2

Jeśli chcesz f_id'S dla wszystkich kombinacji airport & thisTime gdzie DT$thisTime jest niższa niż DT_LU$thisTime, można to osiągnąć poprzez utworzenie nowej zmiennej (lub zastąpienie istniejącej thisTime) za pomocą funkcji ceiling. Przykład, w którym tworzę nowy zmienna thisTime2 a następnie wykonaj normalne połączenie z DT_LU:

DT[, thisTime2 := ceiling(thisTime)]
setkey(DT, airport, thisTime2)[DT_LU, nomatch=0]

Co daje:

   t_id airport thisTime thisTime2 f_id
1:    1       a      5.1         6    1
2:    4       a      5.1         6    1
3:    3       a      5.1         6    1
4:    1       a      5.1         6    2
5:    4       a      5.1         6    2
6:    3       a      5.1         6    2
7:    2       d      6.2         7    2
8:    5       d      6.2         7    2

Zastosowane do podanych danych:

> dt[, thisTime2 := ceiling(thisTime)]
> setkey(dt, airport, thisTime2)[dt_lookup, nomatch=0]

   t_id airport thisTime thisTime2 f_id
1:    1       a      5.1         6    1
2:    3       a      5.1         6    1
3:    1       a      5.1         6    2
4:    3       a      5.1         6    2

Jeśli chcesz dołączyć al przyszłe wartości zamiast tylko pierwszej, potrzebujesz nieco innego podejścia, dla którego będziesz potrzebował funkcjonalności i.col (która nie jest jeszcze udokumentowana):

1: najpierw ustaw klucz tylko na kolumny airport:

setkey(DT, airport)
setkey(DT_LU, airport)

2: użyj i.col funkcjonalność (która nie jest jeszcze udokumentowana) w j, aby uzyskać to, co chcesz w następujący sposób:

DT1 <- DT_LU[DT, .(tid = i.t_id,
                   tTime = i.thisTime,
                   fTime = thisTime[i.thisTime < thisTime],
                   fid = f_id[i.thisTime < thisTime]),
             by=.EACHI]

To daje:

> DT1
    airport tid tTime fTime 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     7   2
11:       d   2   6.2     9   1
12:       d   5   6.2     7   2
13:       d   5   6.2     9   1

Niektóre wyjaśnienia: w przypadku łączenia dwóch tabel danych, w których używane są te same nazwy kolumn, można odnieść się do kolumn z datatable w i, poprzedzając nazwy kolumn i.. Teraz Można porównać thisTime z DT z thisTime z DT_LU. Z by = .EACHI zapewniasz, że wszystkie kombinacje dla z warunkiem są zawarte w wynikowym datatable.

Alternatywnie, można osiągnąć to samo z:

DT2 <- DT_LU[DT, .(airport=i.airport,
                   tid=i.t_id,
                   tTime=i.thisTime,
                   fTime=thisTime[i.thisTime < thisTime],
                   fid=f_id[i.thisTime < thisTime]),
             allow.cartesian=TRUE]

Co daje ten sam wynik:

> identical(DT1, DT2)
[1] TRUE

Jeśli chcesz zawrzeć przyszłe wartości tylko w określonej granicy, możesz użyć:

DT1 <- DT_LU[DT, 
             {
               idx = i.thisTime < thisTime & thisTime - i.thisTime < 2
               .(tid  = i.t_id,
                 tTime = i.thisTime,
                 fTime = thisTime[idx],
                 fid = f_id[idx])
               },
             by=.EACHI]

Co daje:

> DT1
   airport tid tTime fTime 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

Kiedy porównasz to z poprzednim wynikiem, zobaczysz, że teraz wiersze 3, 6, 9, 10 i 12 zostały usunięte.


Dane:

DT <- data.table(t_id = c(1,4,2,3,5),
                 airport = c("a","a","d","a","d"),
                 thisTime = c(5.1, 5.1, 6.2, 5.1, 6.2),
                 key=c("airport","thisTime"))

DT_LU <- data.table(f_id = c(rep(1,4),rep(2,3)),
                    airport = c("a","b","c","d","a","d","e"),
                    thisTime = c(6,7,8,9,6,7,8),
                    key=c("airport","thisTime"))
 21
Author: Jaap,
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
2015-11-22 07:28:27