Series: Labelled Columns
Intuition
A NumPy array is a row of numbers addressed by position. A pandas Series is a NumPy array
plus a label for every value — like a dict that also supports vectorised arithmetic.
Labels make data self-describing: prices["apple"] instead of prices[3].
Precise explanation
import pandas as pd
s = pd.Series({"apple": 1.2, "pear": 0.8, "fig": 2.5})
s["pear"] # 0.8 — by label
s.index # Index(['apple', 'pear', 'fig'], dtype=...)
s.values # the underlying NumPy array
s[s > 1.0] # boolean mask, as in NumPy: apple and fig
s.mean(), s.max() # reductions
s.nlargest(2) # the two largest values with their labels
pd.Series(["a", "b", "a"]).value_counts() # counts of each value, largest first
- Alignment:
a + bmatches values by label, not position. A label present in only one Series givesNaN(missing).a.add(b, fill_value=0)treats a missing side as 0 instead. .to_dict()turns a Series back into a dict;.index.tolist()gives the labels.
| Task | dict version | Series version |
|---|---|---|
| add matching keys | `{k: a.get(k, 0) + b.get(k, 0) for k in a.keys() | b.keys()}` |
| keys with value above the mean | loop + sum(d.values()) / len(d) |
s[s > s.mean()] |
| counts | Counter(items) |
pd.Series(items).value_counts() |
Worked example
a = pd.Series({"x": 1, "y": 2}); b = pd.Series({"y": 10, "z": 5})
a + b # x NaN, y 12, z NaN
a.add(b, fill_value=0) # x 1.0, y 12.0, z 5.0
Common mistakes
- Expecting
a + bto pair values by position. s[0]on a Series with string labels: uses.iloc[0]for positions ands.loc[...]ors[...]for labels.- Forgetting that
value_countsdrops missing values unlessdropna=False.
Why this matters
Every DataFrame column is a Series (PD-02), and label alignment is what makes joins and group-by results line up correctly.
References
- Intro to data structures (pandas 3.1.0 docs) — pandas development team (
S084) - 10 minutes to pandas (pandas 3.1.0 docs) — pandas via NumFOCUS (
S008)