Złączenia lewostronne i prawostronne
Wykonuj złączenia lewostronne i prawostronne, aby zachować wszystkie wiersze z jednej tabeli i dopasować do nich rekordy z drugiej.
Złączenia lewostronne i prawostronne to bezpłatna lekcja Pandas & NumPy Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Pandas & NumPy Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Pandas & NumPy Academy zawiera 4 lekcji w sumie.
Asymetryczne złączenia
Złączenia wewnętrzne i zewnętrzne traktują obie ramki danych symetrycznie. Często jednak chcą Państwo zachować wszystkie rekordy z jednej tabeli, wzbogacając je danymi z innej. Właśnie do tego służą złączenia lewostronne i prawostronne. Te asymetryczne złączenia są niezwykle częste w analizie danych: zachowanie wszystkich transakcji i dodanie nazw produktów tam, gdzie są dostępne; zachowanie wszystkich użytkowników i dodanie daty ich ostatniego zakupu, jeśli ją mają.
Złączenie lewostronne: zachowanie wszystkich wierszy z lewej strony
Złączenie lewostronne (how='left') zachowuje każdy wiersz z lewej ramki danych. W przypadku wierszy, dla których znaleziono pasujący klucz w prawej ramce danych, kolumny z prawej strony są wypełniane dopasowanymi wartościami. Wiersze bez dopasowania mają w kolumnach z prawej strony wartość NaN. Liczba wierszy wyniku zawsze odpowiada liczbie wierszy lewej ramki danych (o ile nie ma zduplikowanych kluczy).
import pandas as pd
orders = pd.DataFrame({
'order_id': [1, 2, 3, 4],
'customer_id': [101, 102, 101, 999],
'amount': [250, 80, 320, 150]
})
customers = pd.DataFrame({
'customer_id': [101, 102, 103],
'name': ['Alice', 'Bob', 'Carol']
})
result = pd.merge(orders, customers, on='customer_id', how='left')
print(result)
# All 4 orders kept; order with customer_id=999 gets NaN for nameStruktura wyniku złączenia lewostronnego
Po złączeniu lewostronnym wiersze z lewej ramki danych, dla których nie znaleziono dopasowania w prawej ramce, będą miały wartość NaN w każdej kolumnie pochodzącej z prawej tabeli. Można to wykorzystać do identyfikowania niedopasowanych wierszy za pomocą filtra boolowskiego na kolumnie prawej tabeli oraz do policzenia, ile wierszy z lewej strony nie miało dopasowania — jest to przydatna kontrola jakości danych.
result = pd.merge(orders, customers, on='customer_id', how='left')
print(result)
# order_id customer_id amount name
# 0 1 101 250 Alice
# 1 2 102 80 Bob
# 2 3 101 320 Alice
# 3 4 999 150 NaN <- no matching customer
# Count unmatched
unmatched = result['name'].isna().sum()
print(f'{unmatched} orders have no customer record')Kiedy używać złączenia lewostronnego
Złączenia lewostronne są odpowiednie, gdy lewa ramka danych jest tabelą główną, a prawa tabela pełni funkcję pomocniczą. Typowe zastosowania to wzbogacanie tabeli faktów o tabelę wymiarów (zamówienia + nazwy produktów), dodawanie opcjonalnych metadanych (użytkownicy + dane profilu) lub obliczanie metryk dla wszystkich rekordów, nawet gdy wyszukiwanie danych się nie powiedzie. W większości kodu analitycznego złączenia lewostronne występują znacznie częściej niż prawostronne.
# Realistic pattern: enrich all products with optional category data
products = pd.DataFrame({'sku': ['A1', 'B2', 'C3'], 'price': [10, 20, 15]})
categories = pd.DataFrame({'sku': ['A1', 'C3'], 'category': ['Tools', 'Home']})
# Keep all products; add category where available
enriched = pd.merge(products, categories, on='sku', how='left')
print(enriched)
# sku price category
# 0 A1 10 Tools
# 1 B2 20 NaN
# 2 C3 15 HomeZłączenie prawostronne: zachowanie wszystkich wierszy z prawej strony
Złączenie prawostronne (how='right') jest lustrzanym odbiciem złączenia lewostronnego: zachowuje każdy wiersz z prawej ramki danych i wstawia NaN w kolumnach lewej tabeli tam, gdzie nie ma dopasowania. Złączenia prawostronne są mniej popularne, ponieważ ten sam wynik można zawsze uzyskać, zamieniając argumenty ramek danych miejscami i używając złączenia lewostronnego, co jest czytelniejsze dla odbiorców kodu.
# Right join: keep all customers, attach orders where they exist
result = pd.merge(orders, customers, on='customer_id', how='right')
print(result)
# All 3 customers appear; Carol (103) has NaN for order_id and amount
# Equivalent left join (swap arguments):
result2 = pd.merge(customers, orders, on='customer_id', how='left')
# Same data, just column order differsPorównanie wszystkich czterech typów złączeń
Cztery typy złączeń różnią się tylko tym, które wiersze z niedopasowanej strony są zachowywane. inner: tylko dopasowane wiersze. outer: wszystkie wiersze z obu stron. left: wszystkie wiersze z lewej strony. right: wszystkie wiersze z prawej strony. W przypadku niedopasowanych wpisów kolumny z nieobecnej strony są wypełniane wartością NaN. Właściwy wybór ma kluczowe znaczenie, aby uniknąć cichego usuwania lub powielania rekordów.
# Summary table
# how='inner' : rows in BOTH tables
# how='left' : ALL left rows + matched right
# how='right' : matched left + ALL right rows
# how='outer' : ALL left rows + ALL right rows
# Test each
for how in ['inner', 'left', 'right', 'outer']:
r = pd.merge(orders, customers, on='customer_id', how=how)
print(f'{how}: {len(r)} rows')Wypełnianie wartości NaN w wynikach złączenia lewostronnego
Po złączeniu lewostronnym niedopasowane wiersze mają wartość NaN w kolumnach prawej tabeli. Często warto zastąpić je rozsądnymi wartościami domyślnymi — na przykład 'Unknown' dla brakującej kategorii lub 0 dla brakującej liczby. Należy użyć fillna() na wyniku albo przekazać fill_value do operacji arytmetycznych wykonywanych po złączeniu.
result = pd.merge(products, categories, on='sku', how='left')
result['category'] = result['category'].fillna('Uncategorised')
print(result)
# sku price category
# 0 A1 10 Tools
# 1 B2 20 Uncategorised
# 2 C3 15 HomeAntyzłączenie lewostronne: wiersze bez dopasowania
Przydatnym wzorcem, który nie jest bezpośrednio obsługiwany przez parametr how, jest antyzłączenie: zachowanie tylko tych wierszy z lewej tabeli, które NIE mają dopasowania w prawej tabeli. Należy zaimplementować je za pomocą złączenia lewostronnego z indicator=True, a następnie odfiltrować wiersze spełniające warunek _merge == 'left_only'. Jest to idealne rozwiązanie do znajdowania osieroconych rekordów, nowych elementów nieobecnych na liście referencyjnej lub transakcji brakujących w rejestrze.
# Anti-join: orders with no matching customer record
result = pd.merge(orders, customers, on='customer_id',
how='left', indicator=True)
unmatched_orders = result[result['_merge'] == 'left_only'].drop(columns='_merge')
print(unmatched_orders)
# order_id customer_id amount name
# 3 4 999 150 NaNZachowywanie liczby wierszy za pomocą złączenia lewostronnego
Gdy prawa ramka danych ma unikatowe klucze, złączenie lewostronne gwarantuje zachowanie dokładnej liczby wierszy z lewej tabeli. Jeśli jednak prawa tabela zawiera zduplikowane wartości kluczy, złączenie lewostronne zwielokrotnia wiersze, podobnie jak złączenie wewnętrzne. Gdy oczekują Państwo relacji jeden-do-wielu, zawsze należy sprawdzić, czy liczba wierszy wyniku odpowiada liczbie wierszy lewej tabeli.
# Right table has duplicate keys -> row multiplication
orders_small = pd.DataFrame({'id': [1, 2], 'amount': [100, 200]})
multi_customer = pd.DataFrame({
'id': [1, 1], # duplicate!
'contact': ['Alice', 'Alice2']
})
result = pd.merge(orders_small, multi_customer, on='id', how='left')
print(len(result)) # 3 rows! order 1 appears twice
print(result)Praktyczny wzorzec złączenia lewostronnego
Oto kompletny przepływ pracy z rzeczywistego zastosowania: należy rozpocząć od rejestru transakcji, wykonać złączenie lewostronne z katalogiem produktów, aby pobrać nazwy, a następnie wykonać złączenie lewostronne z tabelą klientów, aby pobrać nazwy. Brakujące dane z wyszukiwania należy uzupełnić wartościami domyślnymi. Łańcuch złączeń lewostronnych zapewnia zachowanie każdego wiersza transakcji, nawet jeśli w tabelach referencyjnych brakuje produktu lub klienta.
transactions = pd.DataFrame({
'txn_id': [1, 2, 3],
'cust_id': [10, 11, 99],
'prod_id': [20, 21, 20],
'total': [50, 30, 70]
})
custs = pd.DataFrame({'cust_id': [10, 11], 'cust_name': ['Alice', 'Bob']})
prods = pd.DataFrame({'prod_id': [20, 21], 'prod_name': ['Widget', 'Gadget']})
result = (
transactions
.merge(custs, on='cust_id', how='left')
.merge(prods, on='prod_id', how='left')
)
print(result)Wybór między złączeniem lewostronnym a wewnętrznym
Wybór między złączeniem lewostronnym a wewnętrznym to decyzja dotycząca logiki biznesowej: czy należy zachować rekordy bez dopasowania w tabeli wyszukiwania, czy po cichu je usunąć? Należy użyć złączenia lewostronnego, gdy brakujące dopasowania są akceptowalne i chcą Państwo zachować wszystkie rekordy główne. Należy użyć złączenia wewnętrznego, gdy brakujące dopasowanie oznacza, że rekord jest nieprawidłowy i powinien zostać wykluczony z analizy. Zawsze należy udokumentować dokonany wybór i jego uzasadnienie.
# Left join: keep all transactions (some may have no product name)
result_left = pd.merge(transactions, prods, on='prod_id', how='left')
print('Left join rows:', len(result_left)) # same as transactions
# Inner join: only transactions with known product
result_inner = pd.merge(transactions, prods, on='prod_id', how='inner')
print('Inner join rows:', len(result_inner)) # may be fewerSzybkie sprawdzenie
Sprawdź, czy rozumieją Państwo złączenia lewostronne i prawostronne omówione w tej lekcji.
Podsumowanie lekcji
W tej lekcji nauczyli się Państwo, że złączenie lewostronne zachowuje wszystkie wiersze z lewej ramki danych, wypełniając kolumny z prawej strony wartością NaN dla niedopasowanych wierszy; złączenie prawostronne jest jego lustrzanym odbiciem; wzorzec antyzłączenia z użyciem indicator=True wyszukuje wiersze z lewej strony bez dopasowania po prawej; a wybór między złączeniem lewostronnym i wewnętrznym jest decyzją dotyczącą logiki biznesowej. Następnie omówimy łączenie ramek danych po indeksie zamiast po kolumnie.
Często zadawane pytania
Czy lekcja „Złączenia lewostronne i prawostronne” jest bezpłatna?
Tak — pełny tekst „Złączenia lewostronne i prawostronne” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Pandas & NumPy Academy, przejdź na CoddyKit PRO. Kurs Pandas & NumPy Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Złączenia lewostronne i prawostronne”?
Wykonuj złączenia lewostronne i prawostronne, aby zachować wszystkie wiersze z jednej tabeli i dopasować do nich rekordy z drugiej. Ćwiczysz Pandas & NumPy Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Pandas & NumPy Academy?
Nie wymagamy żadnego doświadczenia. Pandas & NumPy Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Złączenia lewostronne i prawostronne”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Pandas & NumPy Academy?
Tak. Każda lekcja Pandas & NumPy Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- pd.concat do układania DataFrame
- pd.merge: złączenia wewnętrzne i zewnętrzne
- Złączenia lewostronne i prawostronne
- Łączenie według indeksu