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 left
i right
któ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'
, left
używane są tylko klucze od , a brakujące dane right
są 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 right
używane są klucze z , a brakujące dane left
są 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 left
tylko 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, left
ma keyLeft
, i right
ma keyRight
zamiast key
-Więc trzeba będzie określić left_on
i right_on
jako 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 keyLeft
od left
i keyRight
od right
, jeśli tylko chcą albo z keyLeft
albo 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 keyLeft
brakuje. 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_on
i 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
, join
iconcat
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_on
i right_on
w 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 left
nazwa 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.join
wartości domyślnych, które są dołączane do indeksu. DataFrame.join
domyś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 lsuffix
i, rsuffix
ponieważ w join
przeciwnym 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: merge
ing wielu DataFrames
Często zdarza się, że wiele DataFrames ma zostać połączonych ze sobą. Naiwnie można to zrobić, łącząc merge
połą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.concat
wielodrożne na unikalnych kluczach oraz połączenia DataFrame.join
wielodroż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.concat
dołą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 join
opisanych poniżej).
Scalanie wielostronne na kluczach z duplikatami
concat
jest 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ć, join
ponieważ może obsłużyć nieunikalne klucze (pamiętaj, że join
dołącza DataFrames do ich indeksu; wywołuje merge
pod 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