To jest trochę filozoficzne pytanie dotyczące składni łączenia danych. Znajduję coraz więcej zastosowań dla danych. Tabele, ale wciąż się uczę ...
Format sprzężenia X[Y]
dla data.tables jest bardzo zwięzły, poręczny i wydajny, ale o ile wiem, obsługuje tylko sprzężenia wewnętrzne i prawe sprzężenia zewnętrzne. Aby uzyskać lewe lub pełne sprzężenie zewnętrzne, muszę użyć merge
:
X[Y, nomatch = NA]
- wszystkie wiersze w Y - prawe sprzężenie zewnętrzne (domyślne)X[Y, nomatch = 0]
- tylko wiersze z dopasowaniami w X i Y - sprzężenie wewnętrznemerge(X, Y, all = TRUE)
- wszystkie rzędy od X i Y - pełne połączenie zewnętrznemerge(X, Y, all.x = TRUE)
- wszystkie wiersze w X - lewe połączenie zewnętrzne
Wydaje mi się, że przydałoby się, gdyby X[Y]
format złączeń obsługiwał wszystkie 4 typy złączeń. Czy jest jakiś powód, dla którego obsługiwane są tylko dwa typy złączeń?
Dla mnie wartości parametrów nomatch = 0
i nomatch = NA
nie są zbyt intuicyjne dla wykonywanych czynności. Łatwiej jest mi zrozumieć i zapamiętać merge
składnię: all = TRUE
, all.x = TRUE
i all.y = TRUE
. Ponieważ X[Y]
operacja przypomina merge
znacznie więcej niż match
, dlaczego nie użyć merge
składni dla złączeń zamiast parametru match
funkcji nomatch
?
Oto przykłady kodu 4 typów złączeń:
# sample X and Y data.tables
library(data.table)
X <- data.table(t = 1:4, a = (1:4)^2)
setkey(X, t)
X
# t a
# 1: 1 1
# 2: 2 4
# 3: 3 9
# 4: 4 16
Y <- data.table(t = 3:6, b = (3:6)^2)
setkey(Y, t)
Y
# t b
# 1: 3 9
# 2: 4 16
# 3: 5 25
# 4: 6 36
# all rows from Y - right outer join
X[Y] # default
# t a b
# 1: 3 9 9
# 2: 4 16 16
# 3: 5 NA 25
# 4: 6 NA 36
X[Y, nomatch = NA] # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
# 3: 5 NA 25
# 4: 6 NA 36
merge(X, Y, by = "t", all.y = TRUE) # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
# 3: 5 NA 25
# 4: 6 NA 36
identical(X[Y], merge(X, Y, by = "t", all.y = TRUE))
# [1] TRUE
# only rows in both X and Y - inner join
X[Y, nomatch = 0]
# t a b
# 1: 3 9 9
# 2: 4 16 16
merge(X, Y, by = "t") # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
merge(X, Y, by = "t", all = FALSE) # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
identical( X[Y, nomatch = 0], merge(X, Y, by = "t", all = FALSE) )
# [1] TRUE
# all rows from X - left outer join
merge(X, Y, by = "t", all.x = TRUE)
# t a b
# 1: 1 1 NA
# 2: 2 4 NA
# 3: 3 9 9
# 4: 4 16 16
# all rows from both X and Y - full outer join
merge(X, Y, by = "t", all = TRUE)
# t a b
# 1: 1 1 NA
# 2: 2 4 NA
# 3: 3 9 9
# 4: 4 16 16
# 5: 5 NA 25
# 6: 6 NA 36
Aktualizacja: data.table v1.9.6 wprowadziła on=
składnię, która umożliwia łączenia ad hoc w polach innych niż klucz podstawowy. odpowiedź jangoreckiego na pytanie Jak łączyć (scalać) ramki danych (wewnętrzne, zewnętrzne, lewe, prawe)? zawiera kilka przykładów dodatkowych typów złączeń, które może obsługiwać data.table.
źródło
Y[X]
, jeśli chcesz lewo sprzężenie zewnętrzne odX[Y]
irbind(Y[X],X[Y])
jeśli chcesz pełne sprzężenie zewnętrzneunique()
podejście poniżej dla pełnego sprzężenia jest lepszerbind(Y[X],X[Y])
, ponieważ rbind wymagałoby skopiowania tabeli. Czy to prawda?unique(c(unique(X[,t]), unique(Y[,t]))
- powinno to być bardziej wydajnepamięć, ponieważ łączy tylko dwie listy, które będą mniejsze lub równe liczbie wierszy w X i Y .Odpowiedzi:
Cytując z
data.table
FAQ 1.11 Jaka jest różnica międzyX[Y]
imerge(X, Y)
?Jeśli chcesz, aby lewe zewnętrzne połączenie
X[Y]
Jeśli chcesz mieć pełne sprzężenie zewnętrzne
źródło
X[Y,all=T]
mógłby być eleganckim sposobem określenia pełnego sprzężenia zewnętrznego w składni data.table X [Y]. LubX[Y,all.x=T]
dla lewego złączenia. Zastanawiałem się, dlaczego nie został zaprojektowany w ten sposób. Tylko myśl.X[Y[J(unique_keys)]]
?Odpowiedź @ mnel jest na miejscu, więc zaakceptuj tę odpowiedź. To tylko kontynuacja, zbyt długa na komentarze.
Jak mówi mnel, lewe / prawe sprzężenie zewnętrzne uzyskuje się przez zamianę
Y
iX
:Y[X]
-vs-X[Y]
. Tak więc 3 z 4 typów złączeń są obsługiwane w tej składni, a nie 2, iiuc.Dodanie czwartego wydaje się dobrym pomysłem. Powiedzmy, że dodajemy
full=TRUE
lubboth=TRUE
lubmerge=TRUE
(nie jesteś pewien najlepszej nazwy argumentu?), To nie przyszło mi do głowy wcześniej, żeX[Y,j,merge=TRUE]
byłoby to przydatne z powodów po ALE w FAQ 1.12. Nowa prośba o funkcję jest teraz dodana i połączona z powrotem tutaj, dzięki:FR # 2301: Dodaj argument merge = TRUE zarówno dla złączenia X [Y], jak i Y [X], tak jak robi to merge ().
Najnowsze wersje przyspieszyły
merge.data.table
(na przykład pobierając płytką kopię wewnętrznie w celu wydajniejszego ustawiania kluczy). Dlatego staramy się przybliżaćmerge()
iX[Y]
przybliżać oraz udostępniać użytkownikowi wszystkie opcje, aby zapewnić pełną elastyczność. Obie mają wady i zalety. Kolejna zaległa prośba o funkcję to:FR # 2033: Dodaj by.x i by.y do merge.data.table
Jeśli są jacyś inni, proszę, niech nadchodzą.
W tej części pytania:
Jeśli wolisz
merge()
składnię i jego 3 argumentyall
,all.x
aall.y
potem po prostu użyć że zamiastX[Y]
. Myślę, że powinno to obejmować wszystkie przypadki. Albo pan myśli, dlaczego jest argument jedennomatch
w[.data.table
? Jeśli tak, to po prostu sposób, który wydawał się naturalny, biorąc pod uwagę FAQ 2.14: „Czy możesz dalej wyjaśnić, dlaczego data.table jest inspirowana składnią A [B] w bazie?”. Alenomatch
obecnie przyjmuje tylko dwie wartości0
iNA
. Można to rozszerzyć tak, aby wartość ujemna coś oznaczała, lub 12 oznaczałoby na przykład użycie wartości 12 wiersza do wypełnienia NA, lubnomatch
w przyszłości może to być wektor lub nawet sam adata.table
.Hm. Jak by -without-by współdziałał z merge = TRUE? Może powinniśmy przejąć to do datatable-help .
źródło
join="all", join="all.x", join="all.y" and join="x.and.y"
na marginesie moich notatek. Nie jestem pewien, czy to jest lepsze.join
tak, dobry pomysł. Wysłałem do datatable-help, więc zobaczmy. Może też poświęćdata.table
trochę czasu na osiedlenie się. Czy na przykład musiałeś już obejść się bez-przez i dołączyć do dziedziczonego zakresu ?join
słowa kluczowego do, kiedy jest DataTable:X[Y,j,join=string]
. Sugerowane możliwe wartości ciągów dla łączenia to: 1) „all.y” i „right” -Ta „odpowiedź” jest propozycją do dyskusji: Jak wskazałem w moim komentarzu, sugeruję dodanie
join
parametru do [.data.table (), aby umożliwić dodatkowe typy złączeń, tjX[Y,j,join=string]
. : . Oprócz 4 typów zwykłych sprzężeń sugeruję również obsługę 3 typów łączeń wyłącznych i łączeń krzyżowych .Proponowane
join
wartości ciągów (i aliasy) dla różnych typów złączeń to:"all.y"
i"right"
- łączenie prawe, obecne data.table default (nomatch = NA) - wszystkie wiersze Y z NA, gdzie nie ma dopasowania X;"both"
oraz"inner"
- łączenie wewnętrzne (nomatch = 0) - tylko wiersze, w których X i Y pasują;"all.x"
i"left"
- left join - wszystkie wiersze z X, NAs, gdzie nie ma dopasowania Y:"outer"
oraz"full"
- pełne sprzężenie zewnętrzne - wszystkie wiersze z X i Y, NA, gdzie nie ma zgodności"only.x"
oraz"not.y"
- non-join lub anti-join zwracające wiersze X, w których nie ma dopasowania Y."only.y"
oraz"not.x"
- non-join lub anti-join zwracające wiersze Y, w których nie ma dopasowania X."not.both"
- łączenie wyłączne zwracające wiersze X i Y, gdzie nie ma dopasowania do innej tabeli, tj. wyłączne lub (XOR)"cross"
- łączenie krzyżowe lub iloczyn kartezjański z każdym wierszem X dopasowanym do każdego wiersza YWartość domyślna
join="all.y"
odpowiada bieżącej wartości domyślnej.Wartości ciągów „all”, „all.x” i „all.y” odpowiadają
merge()
parametrom. Łańcuchy „prawy”, „lewy”, „wewnętrzny” i „zewnętrzny” mogą być bardziej odpowiednie dla użytkowników SQL.Ciągi „zarówno”, jak i „not.both” to moja najlepsza propozycja w tej chwili - ale ktoś może mieć lepsze sugestie dotyczące łączenia wewnętrznego i wyłącznego. (Nie jestem pewien, czy „wyłączność” to właściwa terminologia, popraw mnie, jeśli istnieje odpowiedni termin na złączenie „XOR”).
Użycie
join="not.y"
jest alternatywą dla składniX[-Y,j]
lubX[!Y,j]
bez złączenia i może być bardziej zrozumiałe (dla mnie), chociaż nie jestem pewien, czy są one takie same (nowa funkcja w data.table w wersji 1.8.3).Łączenie krzyżowe może być czasami przydatne, ale może nie pasować do paradygmatu data.table.
źródło
join
ale jeśli nie dostanie się do trackera, zostanie zapomniany.