Ten post ma na celu dać czytelnikom podstawowe informacje na temat łączenia o smaku SQL z pandami, jak z niego korzystać, a kiedy nie.
W szczególności oto, przez co przejdzie ten post:
Przez co ten post nie przejdzie:
- Dyskusje i terminy związane z wynikami (na razie). Głównie godne uwagi wzmianki o lepszych alternatywach, tam gdzie to właściwe.
- Obsługa sufiksów, usuwanie dodatkowych kolumn, zmiana nazw wyników i inne szczególne przypadki użycia. Są inne (czytaj: lepiej) posty, które sobie z tym radzą, więc wymyśl to!
Uwaga:
Większość przykładów domyślnie wykonuje operacje WEJŚCIA WEWNĘTRZNEGO podczas demonstrowania różnych funkcji, chyba że określono inaczej.
Ponadto wszystkie dane DataFrames tutaj można skopiować i powielić, aby można było z nimi grać. Zobacz także ten post
na temat odczytywania ramek danych ze schowka.
Na koniec wszystkie wizualne przedstawienia operacji JOIN zostały ręcznie narysowane przy użyciu Rysunków Google. Inspiracja stąd .
Dość gadania, po prostu pokaż mi, jak używać merge!
Ustawiać
np.random.seed(0)
left = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value': np.random.randn(4)})
right = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value': np.random.randn(4)})
left
key value
0 A 1.764052
1 B 0.400157
2 C 0.978738
3 D 2.240893
right
key value
0 B 1.867558
1 D -0.977278
2 E 0.950088
3 F -0.151357
Dla uproszczenia kolumna klucza ma tę samą nazwę (na razie).
INNER JOIN jest reprezentowany przez

Uwaga
To, wraz z nadchodzącymi liczbami, wszystkie są zgodne z tą konwencją:
- niebieski oznacza wiersze obecne w wyniku scalania
- czerwony oznacza wiersze wykluczone z wyniku (tj. usunięte)
- zielony oznacza brakujące wartości, które w wyniku są zastępowane NaN
Aby wykonać mergeŁĄCZENIE WEWNĘTRZNE, wywołaj lewą ramkę DataFrame, określając prawą ramkę DataFrame i klucz łączenia (przynajmniej) jako argumenty.
left.merge(right, on='key')
# Or, if you want to be explicit
# left.merge(right, on='key', how='inner')
key value_x value_y
0 B 0.400157 1.867558
1 D 2.240893 -0.977278
To zwraca tylko wiersze z lefti rightktóre mają wspólny klucz (w tym przykładzie „B” i „D).
LEWO ZEWNĘTRZNE Dołącz lub LEWO Dołącz jest reprezentowana przez

Można to zrobić, określając how='left'.
left.merge(right, on='key', how='left')
key value_x value_y
0 A 1.764052 NaN
1 B 0.400157 1.867558
2 C 0.978738 NaN
3 D 2.240893 -0.977278
Ostrożnie zanotuj tutaj położenie NaN. Jeśli określisz how='left', leftużywane są tylko klucze od , a brakujące dane rightsą zastępowane przez NaN.
I podobnie, dla PRAWEGO DOŁĄCZENIA ZEWNĘTRZNEGO lub PRAWEGO DOŁĄCZENIA, które jest ...

... określ how='right':
left.merge(right, on='key', how='right')
key value_x value_y
0 B 0.400157 1.867558
1 D 2.240893 -0.977278
2 E NaN 0.950088
3 F NaN -0.151357
Tutaj rightużywane są klucze z , a brakujące dane leftsą zastępowane przez NaN.
Wreszcie, w przypadku PEŁNEGO DOŁĄCZENIA ZEWNĘTRZNEGO , podanego przez

określić how='outer'.
left.merge(right, on='key', how='outer')
key value_x value_y
0 A 1.764052 NaN
1 B 0.400157 1.867558
2 C 0.978738 NaN
3 D 2.240893 -0.977278
4 E NaN 0.950088
5 F NaN -0.151357
Wykorzystuje klucze z obu ramek, a NaN są wstawiane dla brakujących wierszy w obu.
Dokumentacja ładnie podsumowuje te różne połączenia:

Inne DOŁĄCZENIA - WYŁĄCZENIE W LEWO, WYŁĄCZENIE W PRAWO, PEŁNE WYŁĄCZENIE / ANTY ŁĄCZENIE
Jeśli potrzebujesz POŁĄCZEŃ W LEWO, z wyłączeniem POŁĄCZEŃ i POŁĄCZEŃ W PRAWO, w dwóch krokach.
Dla LEWEGO-Z WYŁĄCZENIEM DOŁĄCZENIA, reprezentowane jako

Zacznij od wykonania LEWEGO POŁĄCZENIA ZEWNĘTRZNEGO, a następnie filtrowania (wyłączając!) Wierszy pochodzących lefttylko z ,
(left.merge(right, on='key', how='left', indicator=True)
.query('_merge == "left_only"')
.drop('_merge', 1))
key value_x value_y
0 A 1.764052 NaN
2 C 0.978738 NaN
Gdzie,
left.merge(right, on='key', how='left', indicator=True)
key value_x value_y _merge
0 A 1.764052 NaN left_only
1 B 0.400157 1.867558 both
2 C 0.978738 NaN left_only
3 D 2.240893 -0.977278 both
I podobnie w przypadku DOŁĄCZENIA DO PRAWA,

(left.merge(right, on='key', how='right', indicator=True)
.query('_merge == "right_only"')
.drop('_merge', 1))
key value_x value_y
2 E NaN 0.950088
3 F NaN -0.151357
Na koniec, jeśli musisz wykonać scalenie, które zachowuje tylko klucze z lewej lub prawej strony, ale nie oba (IOW, wykonanie ANTI-JOIN ),

Możesz to zrobić w podobny sposób—
(left.merge(right, on='key', how='outer', indicator=True)
.query('_merge != "both"')
.drop('_merge', 1))
key value_x value_y
0 A 1.764052 NaN
2 C 0.978738 NaN
4 E NaN 0.950088
5 F NaN -0.151357
Różne nazwy dla kluczowych kolumn
Jeśli klucz kolumny są nazywane różnie, na przykład, leftma keyLeft, i rightma keyRightzamiast key-Więc trzeba będzie określić left_oni right_onjako argumenty zamiast on:
left2 = left.rename({'key':'keyLeft'}, axis=1)
right2 = right.rename({'key':'keyRight'}, axis=1)
left2
keyLeft value
0 A 1.764052
1 B 0.400157
2 C 0.978738
3 D 2.240893
right2
keyRight value
0 B 1.867558
1 D -0.977278
2 E 0.950088
3 F -0.151357
left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')
keyLeft value_x keyRight value_y
0 B 0.400157 B 1.867558
1 D 2.240893 D -0.977278
Unikanie zduplikowanej kolumny klucza w danych wyjściowych
Podczas łączenia na keyLeftod lefti keyRightod right, jeśli tylko chcą albo z keyLeftalbo keyRight(ale nie oba) na wyjściu, można uruchomić poprzez ustawienie wskaźnika jako wstępny krok.
left3 = left2.set_index('keyLeft')
left3.merge(right2, left_index=True, right_on='keyRight')
value_x keyRight value_y
0 0.400157 B 1.867558
1 2.240893 D -0.977278
Porównaj to z wyjściem polecenia tuż przed (to jest wyjście z left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')), zauważysz, że keyLeftbrakuje. Możesz dowiedzieć się, którą kolumnę zachować, na podstawie tego, który indeks ramki jest ustawiony jako klucz. Może to mieć znaczenie, gdy powiedzmy, wykonując operację JOIN ZEWNĘTRZNY.
Scalanie tylko jednej kolumny z jednej z DataFrames
Rozważmy na przykład
right3 = right.assign(newcol=np.arange(len(right)))
right3
key value newcol
0 B 1.867558 0
1 D -0.977278 1
2 E 0.950088 2
3 F -0.151357 3
Jeśli musisz scalić tylko „new_val” (bez żadnej innej kolumny), zwykle możesz po prostu podgrupować kolumny przed scaleniem:
left.merge(right3[['key', 'newcol']], on='key')
key value newcol
0 B 0.400157 0
1 D 2.240893 1
Jeśli wykonujesz lewe połączenie zewnętrzne, bardziej wydajne rozwiązanie wymagałoby map:
# left['newcol'] = left['key'].map(right3.set_index('key')['newcol']))
left.assign(newcol=left['key'].map(right3.set_index('key')['newcol']))
key value newcol
0 A 1.764052 NaN
1 B 0.400157 0.0
2 C 0.978738 NaN
3 D 2.240893 1.0
Jak wspomniano, jest to podobne, ale szybsze niż
left.merge(right3[['key', 'newcol']], on='key', how='left')
key value newcol
0 A 1.764052 NaN
1 B 0.400157 0.0
2 C 0.978738 NaN
3 D 2.240893 1.0
Scalanie w wielu kolumnach
Aby przyłączyć się do więcej niż jednej kolumnie, należy określić listę dla on(lub left_oni right_on, w razie potrzeby).
left.merge(right, on=['key1', 'key2'] ...)
Lub, jeśli nazwy są różne,
left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])
Inne przydatne merge*operacje i funkcje
Ta sekcja obejmuje tylko podstawowe informacje i ma na celu tylko zaostrzenie apetytu. Więcej przykładów i przypadków, zobacz dokumentację merge, joiniconcat jak również linki do specyfikacji funkcyjnych.
Na podstawie indeksu * -JOIN (+ kolumna indeksu merge)
Ustawiać
np.random.seed([3, 14])
left = pd.DataFrame({'value': np.random.randn(4)}, index=['A', 'B', 'C', 'D'])
right = pd.DataFrame({'value': np.random.randn(4)}, index=['B', 'D', 'E', 'F'])
left.index.name = right.index.name = 'idxkey'
left
value
idxkey
A -0.602923
B -0.402655
C 0.302329
D -0.524349
right
value
idxkey
B 0.543843
D 0.013135
E -0.326498
F 1.385076
Zazwyczaj scalanie indeksu wyglądałoby następująco:
left.merge(right, left_index=True, right_index=True)
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Obsługa nazw indeksów
Jeśli Twój indeks ma nazwę, użytkownicy wersji v0.23 mogą również określić nazwę poziomu na on(lub left_oni right_onw razie potrzeby).
left.merge(right, on='idxkey')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Scalanie na indeksie jednej kolumny (kolumn) innej
Możliwe jest (i dość proste) użycie indeksu jednego i kolumny drugiego, aby wykonać scalenie. Na przykład,
left.merge(right, left_on='key1', right_index=True)
Lub odwrotnie ( right_on=...i left_index=True).
right2 = right.reset_index().rename({'idxkey' : 'colkey'}, axis=1)
right2
colkey value
0 B 0.543843
1 D 0.013135
2 E -0.326498
3 F 1.385076
left.merge(right2, left_index=True, right_on='colkey')
value_x colkey value_y
0 -0.402655 B 0.543843
1 -0.524349 D 0.013135
W tym szczególnym przypadku leftnazwa indeksu jest nazywana, więc możesz także użyć nazwy indeksu z left_on:
left.merge(right2, left_on='idxkey', right_on='colkey')
value_x colkey value_y
0 -0.402655 B 0.543843
1 -0.524349 D 0.013135
DataFrame.join
Oprócz nich istnieje inna zwięzła opcja. Możesz użyć DataFrame.joinwartości domyślnych, które są dołączane do indeksu. DataFrame.joindomyślnie wykonuje POŁĄCZENIE ZEWNĘTRZNE, więc how='inner'jest to konieczne tutaj.
left.join(right, how='inner', lsuffix='_x', rsuffix='_y')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Zauważ, że musiałem podać argumenty lsuffixi, rsuffixponieważ w joinprzeciwnym razie wystąpiłby błąd:
left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')
Ponieważ nazwy kolumn są takie same. Nie byłoby problemu, gdyby były inaczej nazwane.
left.rename(columns={'value':'leftvalue'}).join(right, how='inner')
leftvalue value
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
pd.concat
Wreszcie, jako alternatywa dla sprzężeń opartych na indeksie, możesz użyć pd.concat:
pd.concat([left, right], axis=1, sort=False, join='inner')
value value
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Pomiń, join='inner'jeśli potrzebujesz PEŁNEGO DOŁĄCZENIA ZEWNĘTRZNEGO (ustawienie domyślne):
pd.concat([left, right], axis=1, sort=False)
value value
A -0.602923 NaN
B -0.402655 0.543843
C 0.302329 NaN
D -0.524349 0.013135
E NaN -0.326498
F NaN 1.385076
Aby uzyskać więcej informacji, zobacz ten kanoniczny post na pd.concat@piRSquared .
Uogólnianie: mergeing wielu DataFrames
Często zdarza się, że wiele DataFrames ma zostać połączonych ze sobą. Naiwnie można to zrobić, łącząc mergepołączenia:
df1.merge(df2, ...).merge(df3, ...)
Jednak to szybko wymyka się spod kontroli wielu DataFrames. Ponadto może być konieczne uogólnienie dla nieznanej liczby ramek danych.
W tym miejscu przedstawiam połączenia pd.concatwielodrożne na unikalnych kluczach oraz połączenia DataFrame.joinwielodrożne na nieunikalnych kluczach. Najpierw konfiguracja.
# Setup.
np.random.seed(0)
A = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'valueA': np.random.randn(4)})
B = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'valueB': np.random.randn(4)})
C = pd.DataFrame({'key': ['D', 'E', 'J', 'C'], 'valueC': np.ones(4)})
dfs = [A, B, C]
# Note, the "key" column values are unique, so the index is unique.
A2 = A.set_index('key')
B2 = B.set_index('key')
C2 = C.set_index('key')
dfs2 = [A2, B2, C2]
Scalanie wielostronne na unikatowych kluczach (lub indeksach)
Jeśli twoje klucze (tutaj klucz może być kolumną lub indeksem) są unikalne, możesz użyć pd.concat. Pamiętaj, że pd.concatdołącza DataFrames do indeksu .
# merge on `key` column, you'll need to set the index before concatenating
pd.concat([
df.set_index('key') for df in dfs], axis=1, join='inner'
).reset_index()
key valueA valueB valueC
0 D 2.240893 -0.977278 1.0
# merge on `key` index
pd.concat(dfs2, axis=1, sort=False, join='inner')
valueA valueB valueC
key
D 2.240893 -0.977278 1.0
Pomiń join='inner'PEŁNE ZŁĄCZE ZEWNĘTRZNE. Zauważ, że nie możesz określić LEWEGO ani PRAWEGO połączenia zewnętrznego (jeśli potrzebujesz, użyj joinopisanych poniżej).
Scalanie wielostronne na kluczach z duplikatami
concatjest szybki, ale ma swoje wady. Nie może obsługiwać duplikatów.
A3 = pd.DataFrame({'key': ['A', 'B', 'C', 'D', 'D'], 'valueA': np.random.randn(5)})
pd.concat([df.set_index('key') for df in [A3, B, C]], axis=1, join='inner')
ValueError: Shape of passed values is (3, 4), indices imply (3, 2)
W tej sytuacji możemy użyć, joinponieważ może obsłużyć nieunikalne klucze (pamiętaj, że joindołącza DataFrames do ich indeksu; wywołuje mergepod maską i wykonuje POŁĄCZENIE ZEWNĘTRZNE, chyba że określono inaczej).
# join on `key` column, set as the index first
# For inner join. For left join, omit the "how" argument.
A.set_index('key').join(
[df.set_index('key') for df in (B, C)], how='inner').reset_index()
key valueA valueB valueC
0 D 2.240893 -0.977278 1.0
# join on `key` index
A3.set_index('key').join([B2, C2], how='inner')
valueA valueB valueC
key
D 1.454274 -0.977278 1.0
D 0.761038 -0.977278 1.0