Series und DataFrame — die zwei Dinge in pandas
Was eine Spalte ist, was eine Tabelle ist und warum alle Werte in einer Spalte denselben Typ haben müssen. Inklusive des Unterschieds zwischen df["col"] und df[["col"]].
Wie möchtest du lernen?
Das Problem, das wir lösen
Im letzten Kapitel wurde eine Zeile geschrieben, und sie hat funktioniert:
print(sales["quantity"].sum())19Die Zeile ist leicht zu lesen, doch in ihr verbirgt sich eine Frage. Was genau hat sales["quantity"] zurückgegeben? Eine Liste? Listen haben kein .sum() — [12, 5, 2].sum() in Python aufzurufen, löst einen Fehler aus.
Es lohnt sich, die Antwort zu kennen, denn in pandas hältst du immer eines von zwei Dingen in der Hand, und fast jede Verwirrung beginnt mit derselben Frage: Was habe ich gerade vor mir? Eine Spalte oder eine ganze Tabelle?
In diesem Kapitel geht es um genau diese zwei Dinge: ihre Namen, ihre Form und was sie voneinander unterscheidet.
Am Ende dieses Kapitels kannst du
- In einem Satz erklären, was eine
Seriesvon einemDataFrameunterscheidet - Eine
Serieserstellen und ihren Index, ihre Werte und ihren Typ separat untersuchen - Erklären, warum alle Werte in einer Spalte denselben Typ haben müssen
df["col"]unddf[["col"]]gezielt einsetzen und wissen, was der Unterschied ist- Einen
KeyErrorlesen und genau sagen, was mit einem Spaltennamen nicht gestimmt hat
Voraussetzungen: Pandas installieren und deine erste Tabelle.
Series — eine Spalte
Beginnen wir mit der kleineren Einheit. Eine Series ist eine Reihe von Werten, von denen jeder mit einem Namen verknüpft ist:
import pandas as pd
quantity = pd.Series([12, 5, 2])
print(quantity)0 12
1 5
2 2
dtype: int64Drei Werte wurden hineingegeben, und drei Paare kamen heraus. Die 0, 1, 2 auf der linken Seite sind der Index — ein Name für jeden Wert. Du hast sie nicht angegeben; pandas hat ab null gezählt.
Und ganz unten steht dtype: int64 — der Typ der gesamten Series. Ein einziger Typ, nicht einer pro Wert. Genau das macht pandas schnell, und es ist gleichzeitig seine wichtigste Einschränkung.
Die drei Teile lassen sich separat betrachten:
import pandas as pd
quantity = pd.Series([12, 5, 2])
print(quantity.index)
print(quantity.values)
print(quantity.dtype)RangeIndex(start=0, stop=3, step=1)
[12 5 2]
int64RangeIndex bedeutet, dass der Index nichts weiter als eine Zählung ist — beginnend bei null, jeweils um eins ansteigend. values liefert die Werte ohne ihre Namen. Und dtype ist der Typ der gesamten Spalte.
Ein Index muss nicht aus Zahlen bestehen:
import pandas as pd
quantity = pd.Series([12, 5, 2], index=["pen", "notebook", "bag"])
print(quantity)
print(quantity["notebook"])pen 12
notebook 5
bag 2
dtype: int64
5Jetzt sind die Zeilen nach den Produkten benannt, und ein Wert kann über diesen Namen abgerufen werden. Das klingt nach einem Python-Dictionary, und die Ähnlichkeit ist real — mit einem großen Unterschied:
import pandas as pd
quantity = pd.Series([12, 5, 2], index=["pen", "notebook", "bag"])
print(quantity * 2)pen 24
notebook 10
bag 4
dtype: int64Die gesamte Spalte wurde auf einmal mit zwei multipliziert, ohne Schleife. Wolltest du das mit einem Dictionary machen, müsstest du jeden Wert selbst durchlaufen. Führst du eine Operation auf einer Series aus, wendet pandas sie auf jeden Wert an — und jedes weitere Kapitel baut auf diesem Verhalten auf.
DataFrame — mehrere Spalten, ein Index
Ein DataFrame besteht aus mehreren Series nebeneinander, die sich einen gemeinsamen Index teilen.
import pandas as pd
sales = pd.DataFrame({
"product": ["pen", "notebook", "bag"],
"quantity": [12, 5, 2],
"price": [15.0, 60.0, 850.0],
})
print(sales)
print(sales.shape)
print(sales.columns)product quantity price
0 pen 12 15.0
1 notebook 5 60.0
2 bag 2 850.0
(3, 3)
Index(['product', 'quantity', 'price'], dtype='object')Die Formulierung „teilen sich einen gemeinsamen Index“ ist der Kern der Sache. Das product, die quantity und der price bei Index 0 beziehen sich alle auf denselben Gegenstand: einen Stift. Der Index ist das, was drei Spalten zu Zeilen verbindet.
Eine Tabelle, mehrere Typen — aber eine Spalte, ein Typ
import pandas as pd
sales = pd.DataFrame({
"product": ["pen", "notebook", "bag"],
"quantity": [12, 5, 2],
"price": [15.0, 60.0, 850.0],
})
print(sales.dtypes)product object
quantity int64
price float64
dtype: objectDrei Spalten, drei Typen. int64 steht für ganze Zahlen, float64 für Dezimalzahlen und object — was in der Regel Text bedeutet.
Beachte, dass es kein str gibt. Die Typen in pandas stammen aus NumPy, wo jeder Wert exakt denselben Speicherplatz belegt — das ist für Zahlen machbar, nicht aber für Text mit variabler Länge. Um Text zu speichern, hält pandas stattdessen Zeiger auf Python-Objekte, und dieses Konstrukt heißt object.
Nun zur wichtigen Regel: Alle Werte in einer Spalte haben denselben Typ. Was passiert also, wenn Zahlen und Text in einer Spalte gemischt werden?
import pandas as pd
mixed = pd.Series([1, "two", 3.0])
print(mixed)
print(mixed.dtype)0 1
1 two
2 3.0
dtype: objectPandas löst keinen Fehler aus — es weist der gesamten Spalte den Typ object zu und fällt damit auf den allgemeinsten verfügbaren Typ zurück. Die Konsequenz ist nicht dramatisch, sondern lautlos: Die Spalte ist nicht mehr numerisch, sodass .mean() fehlschlägt und .sum() beginnt, Text aneinanderzuhängen. Ein einziges verirrtes N/A in einer CSV-Zeile führt genau dazu — und das ist das Thema von Kapitel sechs.
Was habe ich vor mir — eine Series oder einen DataFrame?
import pandas as pd
sales = pd.DataFrame({
"product": ["pen", "notebook", "bag"],
"quantity": [12, 5, 2],
"price": [15.0, 60.0, 850.0],
})
column = sales["quantity"]
print(type(column))
print(type(sales))
print(column.mean())<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>
6.333333333333333Und da ist die Antwort auf die Frage, mit der dieses Kapitel begonnen hat. sales["quantity"] ist keine Liste, sondern eine Series — und eine Series besitzt .sum(), .mean(), .max() und den Rest.
Hier gibt es auch zwei Schreibweisen, bei denen anfangs jeder stutzt:
import pandas as pd
sales = pd.DataFrame({
"product": ["pen", "notebook", "bag"],
"quantity": [12, 5, 2],
"price": [15.0, 60.0, 850.0],
})
print(sales["quantity"])
print("---")
print(sales[["quantity"]])0 12
1 5
2 2
Name: quantity, dtype: int64
---
quantity
0 12
1 5
2 2Ein zusätzliches Klammerpaar, und das Ergebnis ist ein völlig anderes Gebilde. Das Erste ist eine Series — eine Spalte, deren Name und Typ darunter ausgegeben werden. Das Zweite ist ein DataFrame — eine Tabelle, die zufällig nur aus einer Spalte besteht, weshalb die Spaltenüberschrift oben steht.
Die Regel lautet: Die inneren eckigen Klammern stehen für eine Liste von Spalten, und wer nach einer Liste fragt, bekommt eine Tabelle zurück. sales[["product", "price"]] liefert also eine Tabelle mit zwei Spalten.
Warum solltest du diesen Unterschied im Kopf behalten? Weil hier die Fehlermeldungen auseinandergehen. EineSeriesbesitzt.mean(), aber keine Spaltennamen; einDataFramewählt Spalten aus, liefert dir aber keine einzelne Zahl. Wenn eine Fehlermeldung besagt, dass ein Objekt kein solches Attribut besitzt, lautet die erste Frage immer: Welches der beiden halte ich gerade eigentlich in der Hand?
Ein vollständiges Beispiel
inventory.py:
import pandas as pd
# Product names become the index, so a row can be reached by name.
stock = pd.DataFrame(
{
"quantity": [12, 5, 2, 30],
"price": [15.0, 60.0, 850.0, 8.0],
},
index=["pen", "notebook", "bag", "eraser"],
)
print(stock)
print()
print("Shape :", stock.shape)
print("Columns :", list(stock.columns))
print("Index :", list(stock.index))
print()
# A column is a Series, so an operation applies to every value at once.
value = stock["quantity"] * stock["price"]
print("Value per product:")
print(value)
print()
print("Total value:", value.sum())quantity price
pen 12 15.0
notebook 5 60.0
bag 2 850.0
eraser 30 8.0
Shape : (4, 2)
Columns : ['quantity', 'price']
Index : ['pen', 'notebook', 'bag', 'eraser']
Value per product:
pen 180.0
notebook 300.0
bag 1700.0
eraser 240.0
dtype: float64
Total value: 2420.0Zwei Dinge sind hier bemerkenswert.
Erstens: stock["quantity"] * stock["price"] hat zwei Series multipliziert und eine weitere Series erzeugt. Pandas hat sie über den Index einander zugeordnet — die Anzahl der Stifte mit dem Preis der Stifte, die der Taschen mit dem Preis der Taschen. Nach Namen, nicht nach der Reihenfolge der Zeilen. Dieses Verhalten ist später die Grundlage für das Verknüpfen zweier Tabellen.
Zweitens: Der Typ der resultierenden Spalte ist float64, obwohl quantity vom Typ int64 war. Die Multiplikation einer ganzen Zahl mit einer Dezimalzahl ergibt eine Dezimalzahl — genau dieselbe Regel wie im normalen Python; pandas tut hier nichts Eigenes.
Wenn etwas schiefgeht
KeyError: 'Quantity' Es gibt keine solche Spalte. Bei Spaltennamen wird zwischen Groß- und Kleinschreibung unterschieden, und Namen aus einer CSV-Datei enthalten oft führende oder nachfolgende Leerzeichen. Führe print(list(df.columns)) aus, um genau zu sehen, was vorhanden ist — die Ausgabe als Liste setzt Anführungszeichen um jeden Namen, sodass jedes Leerzeichen sichtbar wird.
AttributeError: 'DataFrame' object has no attribute 'mean_price' df.column_name greift ebenfalls auf eine Spalte zu, allerdings nur bei einfachen Namen — nicht, wenn der Name ein Leerzeichen enthält, mit einer Ziffer beginnt oder mit einer pandas-Methode wie count kollidiert. df["column_name"] funktioniert immer, gewöhne dir also an, immer diese Variante zu schreiben.
TypeError: unsupported operand type(s) bei Berechnungen auf einer numerischen Spalte Die Spalte ist wahrscheinlich nicht numerisch. Überprüfe df.dtypes; steht dort object, hat sich irgendwo Text eingeschlichen.
.sum() verkettet Text, statt Zahlen zu addieren Gleiche Ursache — die Spalte ist vom Typ object. Ein einziges N/A oder eine leere Zelle in einer einzigen Zeile reicht aus, um den Typ der gesamten Spalte zu ändern.
ValueError: All arrays must be of the same length Die an pd.DataFrame({...}) übergebenen Listen sind nicht alle gleich lang. Jede Spalte benötigt dieselbe Anzahl an Werten, da sich die Zeilen an einem gemeinsamen Index ausrichten müssen.
Schritt 4 von 6 — Vorhersagen
Prüfe dein Verständnis
Drei Werte wurden übergeben. Was genau wird ausgegeben?
import pandas as pd
quantity = pd.Series([12, 5, 2])
print(quantity)- A12 5 2
- B[12, 5, 2]
- C12 5 2 dtype: int64
- D0 12 1 5 2 2 dtype: int64
Die beiden Zeilen unterscheiden sich nur durch ein zusätzliches Klammerpaar. Was gibt type() zurück?
import pandas as pd
sales = pd.DataFrame({
"product": ["pen", "notebook", "bag"],
"quantity": [12, 5, 2],
"price": [15.0, 60.0, 850.0],
})
print(type(sales["quantity"]))
print(type(sales[["quantity"]]))- ABeide eine Series
- BBeide ein DataFrame
- CDas erste eine Series, das zweite ein DataFrame
- DDas erste ein DataFrame, das zweite eine Series
Zahlen und Text wurden in einer Spalte gemischt. Was macht pandas?
import pandas as pd
mixed = pd.Series([1, "two", 3.0])
print(mixed.dtype)- AEs löst keinen Fehler aus — es setzt den Typ der gesamten Spalte auf `object`
- BEin `TypeError` — zwei Typen können nicht in einer Spalte existieren
- CEs verwirft den Text und behält die Spalte als `float64`
- DEs behält für jeden Wert einen eigenen Typ bei
Zum Antworten brauchst du ein Konto
Melde dich an, um deine Antworten zu prüfen
Die Fragen stehen oben, und sie im Kopf durchzuarbeiten ist der wichtige Teil. Melde dich an, um die Antworten, die Erklärungen und die dreistufigen Hinweise zu sehen.
Jetzt bist du dran
Erstelle eine Datei namens library.py, die einen DataFrame mit mindestens fünf Büchern enthält — die Buchtitel als Index sowie Spalten für die Anzahl der Exemplare (ganze Zahlen), den Preis (Dezimalzahlen) und den Namen des Autors (Text).
Gib dann Folgendes aus:
- Die gesamte Tabelle, ihren
shapeund ihredtypes - Die Preis-Spalte für sich allein — und zeige mit
type(), dass es sich um eineSerieshandelt - Die Preis-Spalte mit doppelten eckigen Klammern — und zeige, dass dies ein
DataFrameist - Den Gesamtwert jedes einzelnen Buches (Exemplare × Preis) sowie die Gesamtsumme über alle Bücher hinweg
Führe danach ein Experiment durch: Ersetze eine der Exemplarzahlen durch "unknown" und führe die Datei erneut aus. Was gibt dtypes nun an, und was ist mit der Gesamtsumme passiert?
Das sind die wertvollsten fünf Minuten in diesem Kapitel. Ein einziges Wort in einer Zelle ändert den Typ einer gesamten Spalte und bringt die Berechnungen durcheinander, ohne einen Fehler auszulösen — und bei echten Daten passiert genau das ständig.
Schritt 6 von 6
Herausforderung — das Kapitel-Quiz
Zehn Fragen von leicht bis schwer. Die letzten sind absichtlich knifflig.
Melde dich an, um das Quiz zu machen