Zum Inhalt
wannacode

Verbinden: merge

Kurz gesagt: merge in pandas verbindet zwei Tabellen über einen gemeinsamen Schlüssel, wie ein JOIN in SQL, und how entscheidet, welche Zeilen bleiben.

Problem

„Welche Kategorie bringt das meiste Geld?“

Der Chef fragt, welche Kategorie am meisten verkauft. Die Bestellzeilen sagen, wie viele Stück welches Produkts gekauft wurden und zu welchem Preis:

PythonDaten: die Tabellen des Shops

Eine Kategorie steht da aber nicht. Es gibt nur product_id, die Produktnummer. Der Name und die Kategorie stehen in products.csv, und der Name der Kategorie steht in einer dritten Tabelle, categories.csv.

Shopdaten sind fast immer so aufgeteilt: Jede Sache steht an einer Stelle, und die anderen Tabellen verweisen mit einer Nummer darauf. Um zu antworten, musst du die Tabellen zu einer verbinden.

Die Idee

Über einen Schlüssel verbinden: merge

merge nimmt jede Zeile der linken Tabelle, sucht in der rechten Tabelle die Zeile mit demselben Wert in der Schlüsselspalte und klebt die beiden Zeilen zu einer zusammen. Das heißt Join, und die Spalte, über die gesucht wird, ist der Schlüssel. In SQL ist dasselbe JOIN.

Hier hat der Schlüssel in jeder Tabelle einen anderen Namen: product_id in den Zeilen, id in den Produkten. left_on und right_on sagen, welche Spalte auf welcher Seite ist:

PythonDaten: die Tabellen des Shops

Die Zeilen bleiben 152, und die Spalten werden 10: die vier aus items und die sechs aus products. Die Spalten product_id und id enthalten dieselbe Zahl, jetzt doppelt.

Deshalb benennst du den Schlüssel meistens zuerst um, damit er überall gleich heißt, und verbindest mit on. Außerdem nimmst du nur die Spalten, die du brauchst:

PythonDaten: die Tabellen des Shops

Sieh es dir an

Wie merge die Paare findet

Hier dasselbe an kleinen Tabellen: 5 Bestellzeilen und eine Preisliste mit 4 Zeilen. In der Preisliste steht der Kaffee (17) zweimal, mit dem alten und dem neuen Preis, und Produkt 26 gibt es noch nicht. Mit how="left" bleibt jede Bestellzeile:

PythonDaten: die Tabellen des Shops

import pandas as pd
lines = pd.DataFrame({
'order_id': [7, 7, 8, 8, 9],
'product_id': [1, 17, 5, 1, 26],
'quantity': [2, 1, 3, 1, 2],
})
catalog = pd.DataFrame({
'product_id': [1, 5, 17, 17],
'name': ['Weißbrot', 'Frischmilch', 'Kaffeebohnen', 'Kaffeebohnen'],
'price': [1.2, 1.6, 13.9, 14.9],
})
both = lines.merge(catalog, on='product_id', how='left')
print(len(lines), len(both))
both
Schritt für Schritt, in Worten
  1. lines sind 5 Bestellzeilen. product_id sagt, welches Produkt gekauft wurde.
  2. catalog ist die Preisliste: 4 Zeilen. Produkt 17 steht zweimal darin, mit dem alten und dem neuen Preis.
  3. Zeile 1: product_id 1. merge sucht alle Zeilen mit 1 in catalog: Weißbrot. Das Paar wird eine Zeile in both.
  4. Zeile 2: product_id 17 steht zweimal in catalog, mit 13,90 € und 14,90 €. Die zwei Paare werden zu zwei Zeilen.
  5. Zeile 3: product_id 5, das ist Frischmilch.
  6. Zeile 4: product_id 1, wieder Weißbrot. Eine Zeile aus catalog kann das Paar vieler Zeilen sein.
  7. Zeile 5: Produkt 26 gibt es nicht in catalog. Mit how='left' bleibt die Zeile, und name und price sind NaN.
  8. 5 Zeilen gingen hinein, 6 kamen heraus: Der wiederholte Schlüssel hat eine Zeile verdoppelt. Deshalb zählst du len vorher und nachher.
  • Jede Bestellzeile sucht alle Zeilen der Preisliste mit derselben product_id.
  • Die Kaffeezeile findet zwei und wird zu zwei Zeilen. Aus fünf Zeilen werden 6.
  • Produkt 26 findet nichts. Mit how="left" bleibt die Zeile, und die Spalten aus der Preisliste sind NaN.

Probier es aus

Wie viele Zeilen?

1. Wenn der Kaffee (17) dreimal in catalog stünde, mit drei Preisen, wie viele Zeilen hätte both für dieselben 5 Bestellzeilen?

Die Idee

Welche Zeilen bleiben: how

Nicht jede Zeile hat ein Paar. Zwei der 20 Kunden haben noch nichts bestellt, und es gibt 60 Bestellungen. Der Parameter how entscheidet, was mit den Zeilen ohne Paar passiert:

PythonDaten: die Tabellen des Shops
  • inner (der Standard): nur die Paare. 60 Zeilen, eine für jede Bestellung. Die Kunden ohne Bestellung sind weg.
  • left: jede Zeile links, mit NaN dort, wo es kein Paar gibt. 62 Zeilen: 60 Bestellungen und die zwei Kunden ohne Bestellung.
  • right: jede Zeile rechts. Hier sind es 60, weil jede Bestellung einen Kunden hat.
  • outer: jede Zeile von beiden Seiten.

indicator=True sagt dir, woher jede Zeile kam. Es fügt eine Spalte _merge mit den Werten both, left_only und right_only hinzu:

PythonDaten: die Tabellen des Shops

Die zwei Kunden ohne Bestellung haben die IDs 19 und 20. right_only ist 0: Keine Bestellung gehört zu einem Kunden, der in der Tabelle fehlt. Wenn doch, wäre das ein Fehler in den Daten, und indicator würde ihn zeigen.

Genauer, für Neugierige

indicator ist die schnellste Prüfung nach einem Join. value_counts() auf _merge sagt dir sofort, wie viele Zeilen kein Paar gefunden haben. Wenn du 0 erwartest und es 300 sind, passen die Schlüssel nicht zusammen: zum Beispiel ist der eine der Text '17' und der andere die Zahl 17.

Probier es aus

Produkte ohne Bewertung

Welche Produkte haben noch gar keine Bewertung? Verbinde products so mit den Bewertungen, dass jedes Produkt bleibt, und lege in no_review nur die Zeilen ohne Paar ab.

PythonDaten: die Tabellen des Shops

Die Idee

Wenn sich der Schlüssel wiederholt

Jetzt will der Chef die Produktbewertung neben jeder Bestellzeile. Die Bewertungen stehen in reviews.csv, und es scheint natürlich, sie über product_id zu verbinden:

PythonDaten: die Tabellen des Shops

Die Zeilen wurden 167 statt 152, und die Summe der Bestellungen sprang von 1.963,50 € auf 2.485,60 €. Der Kaffee hat 3 Bewertungen, also bildete jede Kaffeezeile mit allen dreien ein Paar und wurde zu drei Zeilen. Die Bratpfanne (22) hat 2 Bewertungen. Nichts stürzt ab, aber die Zahlen sind jetzt falsch.

Deshalb zählst du die Zeilen vor und nach jedem Join. Wenn die rechte Tabelle eine Zeile pro Schlüssel haben soll, sag es pandas mit validate:

PythonDaten: die Tabellen des Shops

validate="many_to_one" heißt „links darf sich der Schlüssel wiederholen, rechts muss er eindeutig sein“. Wenn nicht, stoppt merge mit MergeError und sagt dir, welcher Schlüssel sich wiederholt. Es gibt auch "one_to_one" und "one_to_many".

Probier es aus

Eine Bewertung auf jeder Zeile

Leg die mittlere Bewertung des Produkts neben jede Bestellzeile. Die Zeilen müssen so viele bleiben, wie sie sind (152), und Produkte ohne Bewertung sollen NaN bekommen.

PythonDaten: die Tabellen des Shops

Die Idee

Zwei Namensspalten: suffixes

Als Nächstes kommt die Kategorie. Sowohl die Produkte als auch die Kategorien haben die Spalten id und name. Nach dem Join behält pandas beide und hängt die Endungen _x (links) und _y (rechts) an. Mit suffixes wählst du sie selbst:

PythonDaten: die Tabellen des Shops

suffixes=("", "_category") lässt die Produktspalten, wie sie sind, und hängt _category an die der Kategorie. Die Geschenkkarte hat keine Kategorie, also ist name_category NaN.

Hier ist die Falle der Lektion. Wenn du how="left" vergisst, wirft der Inner Join die Geschenkkarte ohne eine einzige Warnung weg:

PythonDaten: die Tabellen des Shops

Aus 152 Zeilen werden 148. Vier Verkäufe der Geschenkkarte, zusammen 240 €, verschwinden aus dem Bericht nach Kategorie. Mit how="left" bleiben die Zeilen 152, und die fehlende Kategorie erscheint als NaN.

Die Idee

Untereinander: concat

Manchmal sollen Tabellen nicht nebeneinander, sondern untereinander geklebt werden. Der Shop hat sein System gewechselt: Die Bestellungen bis Ende 2025 wurden aus dem alten exportiert, die ab 2026 aus dem neuen, mit denselben Spalten. pd.concat stapelt sie zu einer Tabelle:

PythonDaten: die Tabellen des Shops

21 + 39 = 60 Zeilen. ignore_index=True nummeriert die Zeilen neu ab 0. Ohne es bleiben die Indizes beider Tabellen erhalten und können sich wiederholen.

Die Datumsangaben sind hier Text wie „2025-09-01“, also stimmt der Vergleich < '2026-01-01' in alphabetischer Reihenfolge mit der zeitlichen Reihenfolge überein. Echte Daten kommen in der Lektion „Datumswerte und Zeitreihen“.

Genauer, für Neugierige

merge sucht Paare über einen Schlüssel und legt die Spalten nebeneinander. concat sucht nichts: Es stapelt die Zeilen (oder mit axis=1 die Spalten) in der Reihenfolge der Tabellen. Wenn die Spalten nicht zusammenpassen, funktioniert concat trotzdem, aber die fehlenden Zellen werden NaN, also vergleiche vorher df.columns beider Tabellen.

Übung

Der Bericht nach Kategorie

Beantworte den Chef: Wie hoch ist der Umsatz jeder Kategorie, ohne die stornierten Bestellungen? Verbinde die Zeilen mit den Bestellungen (für status), mit den Produkten (für category_id) und mit den Kategorien, sodass nach jedem Join noch 152 Zeilen da sind. Produkte ohne Kategorie kommen unter „Keine Kategorie“. Lege das Ergebnis in by_category ab.

PythonDaten: die Tabellen des Shops

Test

Teste dich

1. Was passiert mit einer Zeile der linken Tabelle, zu der es rechts keine Zeile mit demselben Schlüssel gibt, wenn du how nicht setzt?
2. 152 Bestellzeilen, mit den Bewertungen über product_id verbunden, wurden zu 167. Warum?
3. Was macht validate="many_to_one"?
4. products und categories haben beide eine Spalte name. Welche Spalten liefert ihre Verbindung?
5. Du hast die Bestellungen aus dem alten und dem neuen System, mit denselben Spalten. Wie machst du daraus eine Tabelle?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·