apply, map & applymap

Reviewed & published by Brayan K

apply, map, and applymap are pandas methods that run your own function across data: map transforms a Series element by element, apply runs a function over a Series or over the rows and columns of a DataFrame, and applymap (now DataFrame.map) touches every single cell.

Part of the free Pandas course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Learn which tool to reach for, how the axis argument changes everything, and how lambdas keep your transformations short.

What You'll Learn in This Lesson

1 Series.apply() and Series.map()

On a single column, Series.apply(func) calls your function once per value and collects the results into a new Series. Series.map does the same when given a function, but it can also take a dictionary to recode values, which is perfect for relabelling categories.

import pandas as pd

prices = pd.Series([10.0, 25.5, 8.99])

# apply a function to every value
with_tax = prices.apply(lambda p: round(p * 1.2, 2))
print(with_tax)
# 12.0, 30.6, 10.79

codes = pd.Series(["S", "M", "L", "S"])

# map with a dictionary to recode each value
labels = codes.map({"S": "Small", "M": "Medium", "L": "Large"})
print(labels.tolist())
# ['Small', 'Medium', 'Large', 'Small']

# map can also take a function, just like apply
print(codes.map(lambda c: c.lower()).tolist())
# ['s', 'm', 'l', 's']

# ✅ Expected output:
# 0    12.00
# 1    30.60
# 2    10.79
# dtype: float64
# ['Small', 'Medium', 'Large', 'Small']
# ['s', 'm', 'l', 's']

2 DataFrame.apply: axis=0 vs axis=1

On a DataFrame, apply hands your function a whole Series at a time. With axis=0 (the default) each column is passed in, so you get one summary per column. With axis=1 each row is passed in, which is how you combine several columns into one new value.

import pandas as pd

df = pd.DataFrame({
    "math": [80, 90, 70],
    "science": [60, 85, 95],
})

# axis=0: function receives each COLUMN -> one result per column
print(df.apply(lambda col: col.max() - col.min()))
# math -> 20, science -> 35

# axis=1: function receives each ROW -> one result per row
df["total"] = df.apply(lambda row: row["math"] + row["science"], axis=1)
print(df)
# total column: 140, 175, 165

# ✅ Expected output:
# math       20
# science    35
# dtype: int64
#    math  science  total
# 0    80       60    140
# 1    90       85    175
# 2    70       95    165

3 Elementwise: applymap (now DataFrame.map)

When you want to transform every individual cell of a DataFrame the same way, use applymap. In pandas 2.1 and later this method was renamed DataFrame.map; both do exactly the same elementwise work, so you may see either name.

import pandas as pd

df = pd.DataFrame({
    "a": [1.5, 2.25],
    "b": [3.1, 4.999],
})

# Format every cell as a 2-decimal string.
# applymap works on all pandas versions...
print(df.applymap(lambda x: f"{x:.2f}"))

# ...and DataFrame.map is the modern equivalent (pandas 2.1+)
print(df.map(lambda x: f"{x:.2f}"))
# Both print:
#       a     b
# 0  1.50  3.10
# 1  2.25  5.00

# ✅ Expected output:
#       a     b
# 0  1.50  3.10
# 1  2.25  5.00
#       a     b
# 0  1.50  3.10
# 1  2.25  5.00

🎯 Your Turn: Pass or Fail

Replace the blank so each score becomes "Pass" when it is 50 or more and "Fail" otherwise. The expected output is a Series with values Pass, Fail, Pass.

import pandas as pd

scores = pd.Series([72, 41, 88])

# 🎯 YOUR TURN: return "Pass" if s >= 50 else "Fail"
result = scores.apply(lambda s: "Pass" if ___ else "Fail")
print(result.tolist())

# Expected output: ['Pass', 'Fail', 'Pass']

Common Errors

❌ Forgetting axis=1 for row logic

Without axis=1, apply walks columns and your row lookup like row["math"] fails or gives the wrong shape.

df.apply(lambda row: row["a"] + row["b"], axis=1)  # ✅ axis=1

❌ Using applymap on a Series

applymap and DataFrame.map only exist on DataFrames. On a single column use Series.apply or Series.map instead.

series.apply(my_func)   # ✅ for a Series
df.map(my_func)         # ✅ for a whole DataFrame

🎯 Mini Challenge: Order Summary

Recode a status column with map, then build a row total with a row-wise apply.

import pandas as pd

df = pd.DataFrame({
    "qty": [2, 1, 3],
    "price": [9.99, 19.5, 4.0],
    "status": ["P", "S", "P"],
})

# 1. Recode the status codes to words with map + a dict
df["status"] = df["status"].map({"P": "Paid", "S": "Shipped"})

# 2. Row-wise apply to compute line totals (axis=1)
df["line_total"] = df.apply(lambda r: round(r["qty"] * r["price"], 2), axis=1)

print(df)
# line_total: 19.98, 19.5, 12.0

# ✅ Expected output:
#    qty  price   status  line_total
# 0    2   9.99     Paid       19.98
# 1    1  19.50  Shipped       19.50
# 2    3   4.00     Paid       12.00

❓ Frequently Asked Questions

Lesson complete — you can transform data your way!

You now know when to use map for recoding, apply for flexible per-column or per-row logic, and applymap / DataFrame.map for every cell. Lambdas keep these transformations short and readable.

Practice quiz

What can Series.map accept that Series.apply cannot?

  • A function
  • A lambda
  • A dictionary for recoding values
  • A Series of numbers

Answer: A dictionary for recoding values. map accepts a dict (or Series) to substitute values, as well as a function; apply only takes a function.

If you map a Series with a dict and a value's key is missing, what happens to that value?

  • It becomes NaN
  • It stays unchanged
  • It raises an error
  • It becomes 0

Answer: It becomes NaN. Values whose key is absent from the mapping dict become NaN.

What does the default axis=0 in DataFrame.apply pass to your function?

  • Each row as a Series
  • A single scalar
  • The whole DataFrame
  • Each column as a Series

Answer: Each column as a Series. axis=0 (the default) passes each column to the function, giving one result per column.

Which axis lets you combine several columns of the same row into one value?

  • axis=0
  • axis=1
  • axis=2
  • axis=-1 only

Answer: axis=1. axis=1 passes each row as a Series, so you can read multiple columns of that row.

Which method transforms every individual cell of a DataFrame the same way?

  • DataFrame.map (formerly applymap)
  • Series.map
  • groupby
  • merge

Answer: DataFrame.map (formerly applymap). applymap, renamed DataFrame.map in pandas 2.1+, applies a function elementwise to every cell.

What replaced the deprecated DataFrame.applymap in pandas 2.1?

  • DataFrame.apply
  • Series.map
  • DataFrame.map
  • DataFrame.transform

Answer: DataFrame.map. DataFrame.map does the same elementwise operation and is the modern name.

For df.apply(lambda col: col.max() - col.min()) on columns math=[80,90,70] and science=[60,85,95], what are the results?

  • math 70, science 60
  • math 20, science 35
  • math 10, science 10
  • An error

Answer: math 20, science 35. Per column: math 90-70=20, science 95-60=35.

Which call correctly computes a per-row total across columns 'a' and 'b'?

  • df.apply(lambda r: r['a'] + r['b'])
  • df.map(lambda r: r['a'] + r['b'])
  • df['a'].applymap(sum)
  • df.apply(lambda r: r['a'] + r['b'], axis=1)

Answer: df.apply(lambda r: r['a'] + r['b'], axis=1). Row logic needs axis=1 so each row Series is passed in.

On a single column, why use apply with a function instead of map with a dict?

  • apply is always faster
  • apply lets you supply default logic for unknown values
  • map cannot take a function
  • map only works on numbers

Answer: apply lets you supply default logic for unknown values. A function in apply can handle any input, including a default for values a dict would map to NaN.

Which method does NOT exist on a Series (only on a DataFrame)?

  • apply
  • map
  • applymap
  • head

Answer: applymap. applymap and DataFrame.map are DataFrame-only; on a Series use apply or map.

Continue this course

Frequently asked questions

What is the difference between map and apply in pandas?

Series.map is used to substitute or transform values element by element, and it accepts a dictionary, a Series, or a function. Series.apply only accepts a function but is more flexible for richer logic. On a DataFrame, apply runs a function over whole columns or rows, which map cannot do.

What does the axis argument do in DataFrame.apply?

axis=0 (the default) passes each column to your function as a Series, so you typically get one result per column. axis=1 passes each row as a Series, so you get one result per row. Use axis=1 when a new value depends on several columns of the same row.

Is applymap removed in newer pandas versions?

DataFrame.applymap was deprecated in pandas 2.1 in favour of DataFrame.map, which does the same elementwise operation. applymap still works for now but emits a warning, so prefer DataFrame.map in new code while knowing both names refer to the same idea.