Data AnalyticsPandas & NumPybeginner
Updated:

Pandas apply, map and applymap

4 min read

apply and map run your own functions over pandas data. Learn Series.map, DataFrame.apply on columns and rows, and why vectorized code is usually faster.

TL;DR – Quick Answer

apply runs a function over a Series or across the rows or columns of a DataFrame, map substitutes each value in a Series using a function or dictionary, and applymap (now DataFrame.map) applies a function element-wise across a whole DataFrame. Use them to transform data with custom logic. When a built-in vectorized operation exists, prefer it because it is faster than apply.

On This Page

Sooner or later a transformation you need is not one of pandas' built-in methods, and you want to run your own logic over the data. That is what apply, map and their relatives are for. They let you push a function through a Series or DataFrame and get a transformed result back. Used well they are powerful; used carelessly they are slow, so this tutorial covers both the how and the when.

The three tools overlap, so the key is knowing which fits each job: map for substituting values in one column, apply for column-wise or row-wise logic, and element-wise map on a whole DataFrame for cell-by-cell work.

map: substitute values in a Series

Series.map transforms each value in one column. Its most useful form takes a dictionary that translates old values to new ones, perfect for recoding categories. Start with a small illustrative sample:

import pandas as pd

df = pd.DataFrame({
    "name": ["Aarti", "Bhaskar", "Chitra", "Devan"],
    "grade": ["A", "B", "A", "C"],
    "salary": [48000, 65000, 52000, 90000],
})

grade_points = {"A": 4.0, "B": 3.0, "C": 2.0}
df["gpa"] = df["grade"].map(grade_points)
print(df)
      name grade  salary  gpa
0    Aarti     A   48000  4.0
1  Bhaskar     B   65000  3.0
2   Chitra     A   52000  4.0
3    Devan     C   90000  2.0

The dictionary mapped each letter grade to a number in one clean line. map also accepts a function, so df["grade"].map(str.lower) would lowercase every grade. Values not present in the dictionary become NaN, which is a useful signal for unexpected categories.

apply on a Series

Series.apply runs a function on each value, much like map, but is the idiomatic choice when you pass a function rather than a lookup. It shines with a lambda for quick inline logic:

df["salary_band"] = df["salary"].apply(
    lambda s: "high" if s >= 60000 else "standard"
)
print(df[["name", "salary", "salary_band"]])
      name  salary salary_band
0    Aarti   48000    standard
1  Bhaskar   65000        high
2   Chitra   52000    standard
3    Devan   90000        high

Each salary passed through the function and produced a label. This is how you build derived, categorical columns from numeric ones.

apply across rows

The real power of apply is axis=1, which hands your function an entire row so you can combine several columns at once:

orders = pd.DataFrame({
    "price": [100, 250, 80],
    "qty": [2, 1, 5],
})
orders["total"] = orders.apply(lambda row: row["price"] * row["qty"], axis=1)
print(orders)
   price  qty  total
0    100    2    200
1    250    1    250
2     80    5    400

With axis=1 the row argument is a Series holding that row's values, so you can reference any column by name. This is invaluable when a new value depends on the interaction of multiple columns. (For this exact multiplication, note that the vectorized orders["price"] * orders["qty"] is faster, a point we return to below.)

Element-wise across a whole DataFrame

To apply a function to every individual cell of a DataFrame, use DataFrame.map (called applymap before pandas 2.1):

nums = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
print(nums.map(lambda x: x ** 2))
   a   b
0  1   9
1  4  16

Every cell was squared. This is for uniform, cell-level transformations across the entire table.

Prefer vectorized operations when you can

Here is the most important habit to build: apply calls your Python function once per element or row, which is slower than pandas' built-in vectorized operations that run in optimized C. Whenever a native operation exists, use it. Arithmetic, comparisons and string methods are all vectorized:

# vectorized: fast, preferred
orders["total"] = orders["price"] * orders["qty"]
df["gpa_bonus"] = df["gpa"] + 0.5

Reach for apply only when the logic genuinely cannot be expressed with vectorized operations or a map dictionary. On small datasets the speed difference is irrelevant, but on millions of rows it is the difference between seconds and minutes.

Practical usage

In real work you use map to recode categories (region codes to names, status flags to labels), apply with a lambda to bucket numbers into bands, and apply(axis=1) for the occasional multi-column calculation that has no vectorized form. A frequent pattern is cleaning: apply a small parsing function to salvage a messy column, then continue with fast vectorized code once the data is tidy. Keeping the vectorized-first mindset means you use these tools deliberately, not as a default hammer.

Common mistakes

  • Reaching for apply when a vectorized op exists. Multiplying two columns or comparing values does not need apply and is much slower with it. Use direct operations first.
  • Calling the function instead of passing it. df["x"].apply(str.upper()) fails; pass the function without parentheses: df["x"].apply(str.upper).
  • Forgetting axis=1 for row logic. By default apply on a DataFrame works column by column. To operate on rows, you must set axis=1.
  • Unmapped values becoming NaN silently. With map, any value missing from your dictionary turns into NaN. Check for unexpected NaN afterwards, or supply a default.

In interviews

Interviewers use apply questions to probe whether you understand performance, not just syntax. A common prompt is "create a derived column based on a rule," where a lambda inside apply is a fine answer, but the standout candidate adds "if this were simple arithmetic I'd vectorize it instead for speed." Expect to explain the difference between map and apply, and to know that applymap became DataFrame.map. Demonstrating that you default to vectorized operations and reserve apply for genuinely custom logic signals maturity with pandas.

Where this fits in your learning path

Custom transformations are a practical middle skill in the data analytics path. apply and map pair especially well with string methods for cleaning text, and with groupby where you sometimes apply a function per group. Understanding why vectorized code is faster connects directly to the NumPy introduction, which explains the array engine underneath. Clean, efficient transformation is a daily part of the data analyst role.

Frequently Asked Questions

What is the difference between apply and map in pandas?
map works only on a Series and substitutes each value using a function, dictionary or another Series. apply is more general: on a Series it transforms each value, and on a DataFrame it runs a function down each column or across each row depending on the axis. Use map for simple value substitution and apply for row-wise or column-wise logic.
How do I apply a function to a pandas column?
Select the column and call apply with your function: df['salary'].apply(lambda x: x * 1.1). The function runs on each value and returns a new Series you can assign back. For a named function, pass its name without parentheses, as in df['name'].apply(str.upper).
How do I apply a function across each row of a DataFrame?
Call df.apply(func, axis=1). With axis=1 the function receives each row as a Series, so you can combine several columns, for example lambda row: row['price'] * row['qty']. With axis=0, the default, the function receives each column instead.
What replaced applymap in newer pandas?
In pandas 2.1 and later, DataFrame.applymap was renamed to DataFrame.map for element-wise application across a whole DataFrame. applymap still works but is deprecated. Both apply a function to every individual cell.
Is apply slow in pandas?
apply can be slower than built-in vectorized operations because it calls your Python function once per element or row instead of using optimized C code. For arithmetic, string or comparison work, prefer vectorized methods and only reach for apply when the logic cannot be expressed vectorially. On small data the difference is negligible.

Want to Build Your Career in Data Analytics with AI?

Join CodeBegun and train with working industry engineers — Explore the Data Analytics program

Apply for Demo Class →
Siva Prasad Galaba
Founder, CodeBegun · Staff Engineer

Founder of CodeBegun. 15+ years building Java systems at companies like Crunchyroll. Teaches Java, Spring Boot and system design the way the industry actually works, and mentors students through projects, mock interviews and placement preparation.

Technically reviewed by CodeBegun Technical TeamLast reviewed 16 July 2026 LinkedIn
Chat with us