map(): Series & DataFrame
Replace or transform values with Series.map (dict, function or Series), handle unmatched values and NaN, and use DataFrame.map — the pandas 3 replacement for applymap.
Your match data stores team codes — MI, CSK, RCB — but the report needs full names. You have a dictionary that says which code means which name. Looking each value up in a dictionary is exactly what map() is for. Notebook 12 uses it for team names, role names and grades.
Definition
Series.map(arg)returns a new Series where every value is replaced by the result of looking it up inarg.argcan be a dict (value → new value), a Series (index → new value), or a function (called once per value). Values that a dict or Series does not contain become NaN.
- dict — the keys are the old values, the dict values are the new ones. Fast look-up.
- Series — works like a dict: its index is matched against your values.
- function — behaves like
Series.applyfor a single value:func(value). - Unmatched → NaN — this is the biggest difference from
replace(), which leaves unmatched values unchanged.
DataFrame.map(func)calls a function on every single cell of a DataFrame and returns a DataFrame of the same shape.
Syntax
python
series.map(arg, na_action=None)
dataframe.map(func, na_action=None, **kwargs)| Parameter | Meaning | Default |
|---|---|---|
arg (Series.map) | a dict, a Series, or a function | required |
func (DataFrame.map) | a function only (no dict) — called on every cell | required |
na_action | "ignore" → missing values are passed through as NaN without calling the function | None |
**kwargs | (DataFrame.map) extra keyword arguments for func | — |
Note (pandas 3):
DataFrame.applymap()was deprecated in 2.1 and removed in 3.0. Calling it now raisesAttributeError: 'DataFrame' object has no attribute 'applymap'. UseDataFrame.map()— same behaviour, new name.
Example — map team codes with a dict
python
import pandas as pd
teams = pd.Series(["MI", "CSK", "RCB", "KKR", "MI", "SRH"])
team_map = {"MI": "Mumbai Indians", "CSK": "Chennai Super Kings",
"RCB": "Royal Challengers Bengaluru", "KKR": "Kolkata Knight Riders"}
print(teams.map(team_map))text
0 Mumbai Indians
1 Chennai Super Kings
2 Royal Challengers Bengaluru
3 Kolkata Knight Riders
4 Mumbai Indians
5 NaN
dtype: strHow it works: every value was looked up in team_map. "SRH" is not a key, so it became NaN. Two fixes:
python
print(teams.map(team_map).fillna("Unknown")) # default for unmatched values
print(teams.replace(team_map)) # replace keeps unmatched values as they aretext
0 Mumbai Indians
1 Chennai Super Kings
2 Royal Challengers Bengaluru
3 Kolkata Knight Riders
4 Mumbai Indians
5 Unknown
dtype: str
0 Mumbai Indians
1 Chennai Super Kings
2 Royal Challengers Bengaluru
3 Kolkata Knight Riders
4 Mumbai Indians
5 SRH
dtype: strExample — map with a function and with a Series
python
runs = pd.Series([120, 45, 75, 30], index=["Virat", "Rohit", "Dhoni", "Gill"])
print(runs.map(lambda r: "50+" if r >= 50 else "below 50"))
print(runs.map("{} runs".format))
captains = pd.Series({"MI": "Hardik", "CSK": "Gaikwad", "RCB": "Patidar"})
print(teams.map(captains))text
Virat 50+
Rohit below 50
Dhoni 50+
Gill below 50
dtype: str
Virat 120 runs
Rohit 45 runs
Dhoni 75 runs
Gill 30 runs
dtype: str
0 Hardik
1 Gaikwad
2 Patidar
3 NaN
4 Hardik
5 NaN
dtype: strHow it works: with a function, map calls it once per value. "{} runs".format is a ready-made function too. With a Series, pandas matches each team code against the Series index (MI, CSK, RCB) — KKR and SRH have no captain entry, so they become NaN.
Example — na_action="ignore"
python
s = pd.Series(["mi", None, "csk"])
print(s.map(lambda x: x.upper(), na_action="ignore"))
s.map(lambda x: x.upper())text
0 MI
1 NaN
2 CSK
dtype: str
AttributeError: 'float' object has no attribute 'upper'How it works: a missing value is stored as NaN, which is a float. Without na_action="ignore", your function receives that float and .upper() fails. With it, pandas skips missing values and leaves them as NaN.
Example — DataFrame.map on every cell
python
sc = pd.DataFrame({"m1": [72.456, 45.1], "m2": [88.0, 0.555]}, index=["Virat", "Rohit"])
print(sc.map(lambda x: f"{x:.1f}"))
print(sc.map(round))text
m1 m2
Virat 72.5 88.0
Rohit 45.1 0.6
m1 m2
Virat 72 88
Rohit 45 1How it works: the function ran on all 4 cells. The first result holds text (str dtype) — great for display, but you can't do maths on it any more. For plain rounding, sc.round(1) is the vectorised, faster choice; use DataFrame.map when there is no built-in method.
Comparison — map vs apply vs replace
Series.map | Series.apply | Series.replace | DataFrame.map | |
|---|---|---|---|---|
| Works on | Series | Series | Series / DataFrame | every cell of a DataFrame |
| Accepts | dict, Series, function | function (+ args) | dict, value, list, regex | function |
| Unmatched values | NaN | n/a | kept unchanged | n/a |
| Extra args | via kwargs (function only) | args=, kwargs | — | kwargs |
| Typical use | code → name look-ups, simple transforms | custom logic, returning a Series | fixing a few specific values | formatting / cleaning each cell |
Common mistakes
- ❌
df.applymap(func)in pandas 3. ✅df.map(func). - ❌ Forgetting that unmatched keys become NaN, then wondering why rows "disappear" after a
dropna(). ✅ Checkresult.isna().sum()or add.fillna(...). - ❌ Using
mapwith a dict when you only want to fix 2 spellings. ✅replace({"Bengaluru": "Bangalore"})keeps everything else. - ❌ A function that crashes on NaN. ✅ Pass
na_action="ignore". - ❌ Trying
df.map({"a": 1})with a dict. ✅DataFrame.maptakes a function; map a dict column by column withdf["col"].map(d).
Interview tip
Q: You map a column with a dictionary and some rows become NaN. Why?
A: Series.map with a dict returns NaN for every value that is not a key in the dict (including spelling/case differences like "mi" vs "MI"). Either complete the dict, normalise the values first (.str.upper()), add .fillna(default), or use replace() which leaves unmatched values alone.
Key points to remember
- Series.map accepts a dict, a Series (matched on its index) or a function, and returns a new Series.
- Values that are not found in the dict/Series become NaN — unlike replace(), which keeps them.
- na_action='ignore' passes missing values straight through without calling your function.
- DataFrame.map(func) runs a function on every cell; it replaces applymap, which was removed in pandas 3.
- DataFrame.map takes only a function; to map a dict, map each column separately.
- Prefer built-in vectorised methods (round, str methods) when they exist — map/apply are Python-level loops.
Try it yourself
Team codes to full names
map with a function, a Series and na_action
DataFrame.map (the new applymap)
Practice: grades from marks
Revision Flashcards
Tap a card to flip it and see the answer.
