Pandas Apply, Map and Applymap Explained
SkillVeris Team
Data Science Team

apply runs a function along a whole row or column, map transforms a single Series element by element, and applymap (now DataFrame.map) applies a function to every individual cell.
In this guide, you'll learn:
- Series.map is for element-wise transforms and value lookups; DataFrame.apply is for row- or column-wise logic controlled by the axis argument.
- applymap was renamed DataFrame.map in Pandas 2.1, though the old name still works for now.
- These methods loop in Python and are slow on large data — prefer vectorised operations or np.where whenever possible.
- map can take a dict or Series to recode categories, replacing verbose if-else chains.
1Apply vs Map vs Applymap: What's the Difference?
The difference is scope. Series.map transforms one Series element by element, DataFrame.apply runs a function across an entire row or column at a time, and applymap (renamed DataFrame.map in Pandas 2.1) applies a function to every single cell of a DataFrame. Picking the right one is about matching the tool to the granularity of your transformation.
All three exist because transformations happen at different levels: individual values, whole rows or columns, or every cell independently. Understanding which object each method lives on removes most of the confusion.
2Series.map — Element-Wise Transforms
map operates on a single Series and applies a function, dict, or Series to each element, returning a new Series of the same length. Its most powerful use is recoding values with a dictionary — a clean replacement for long if-else chains.
- df['grade'] = df['score'].map(lambda x: 'pass' if x >= 50 else 'fail')
- df['code'] = df['country'].map({'India': 'IN', 'United States': 'US'})
- df['upper'] = df['name'].map(str.upper)
💡map With a Dict Is a Lookup Table
Passing a dictionary to map turns it into a fast recoding tool. Any value missing from the dict becomes NaN, which doubles as a handy way to flag unexpected categories.
3DataFrame.apply — Row or Column Logic
apply runs a function along an axis of a DataFrame. With axis=0 (the default) the function receives each column as a Series; with axis=1 it receives each row. Row-wise apply is the go-to when a calculation needs several columns at once.
- df.apply(lambda col: col.max() - col.min()) # per-column range (axis=0)
- df.apply(lambda row: row['price'] * row['qty'], axis=1) # per-row calc
- df[['a', 'b']].apply(np.sqrt) # apply a ufunc column-wise
The axis Argument Trips Everyone Up
Remember that axis=1 means 'apply across the columns for each row', so your function receives a full row. axis=0 means 'apply down each column'. Many bugs come from picking the wrong axis, so test on a small slice first and check the shape of the result.
4applymap and Its New Name
applymap applies a function to every individual cell of a DataFrame, independent of rows and columns. It is useful for uniform formatting, like rounding or string cleaning across a whole frame. As of Pandas 2.1 it was renamed DataFrame.map for consistency with Series.map; applymap still works but is deprecated in favour of the new name.
- df.map(lambda x: f'{x:.2f}') # format every cell (Pandas 2.1+)
- df.applymap(lambda x: x * 2) # older equivalent, still works
- df.map(lambda x: x.strip() if isinstance(x, str) else x)
5Why Vectorisation Usually Wins
apply, map, and applymap all loop in Python under the hood, so they are far slower than vectorised operations that run in optimised C. For anything performance-sensitive, express your logic with native operators, built-in methods, or NumPy first.
Most element-wise transformations have a vectorised equivalent that is both faster and easier to read once you know it exists.
- df['total'] = df['price'] * df['qty'] # beats a row-wise apply
- df['grade'] = np.where(df['score'] >= 50, 'pass', 'fail') # beats map with lambda
- df['clean'] = df['name'].str.strip().str.lower() # vectorised string methods
- df['tier'] = pd.cut(df['score'], bins=[0, 50, 80, 100], labels=['low', 'mid', 'high'])
🔑Reach for apply Last
Try a vectorised operator, then a built-in .str or .dt accessor, then np.where or np.select. Use apply only when none of those can express the logic.
6Common Mistakes to Avoid
These methods are flexible, which makes it easy to misuse them.
- Using apply(axis=1) for arithmetic that a plain column expression handles far faster.
- Calling map on a DataFrame instead of a Series — map is a Series method (or DataFrame.map for cells), not a row/column tool.
- Forgetting axis on apply, so a row calculation silently runs column-wise.
- Returning inconsistent shapes from an apply function, which produces confusing object-dtype results.
- Reaching for apply reflexively when str, dt, np.where, or pd.cut would be clearer and quicker.
⚠️apply Is Not Free
On millions of rows, a Python-level apply can be orders of magnitude slower than a vectorised expression. Profile before you assume apply is fine at scale.
7A Quick Decision Guide
When you are unsure which method to use, work down this short list.
- Transforming one column value by value? Series.map (or a dict for recoding).
- Need several columns of a row together? DataFrame.apply with axis=1.
- Same function on every cell of a frame? DataFrame.map (formerly applymap).
- A simple arithmetic or string transform? Skip all three — vectorise it.
8Key Takeaways
Match the method to the scope of your transformation.
- map = element-wise on a Series; apply = row/column on a DataFrame; applymap/DataFrame.map = every cell.
- map with a dict is an elegant category recoder.
- apply's axis argument decides row-wise (1) versus column-wise (0).
- applymap is now DataFrame.map in Pandas 2.1+.
- Vectorised operations beat all three for speed and readability — use apply last.
9Frequently Asked Questions
Q: Is map faster than apply in Pandas? A: For element-wise work on a single Series, map is usually a little faster and clearer than apply because it is purpose-built for that scope. But both loop in Python, so a vectorised operation or np.where will typically outperform either on large data.
Q: What replaced applymap in newer Pandas? A: Pandas 2.1 renamed applymap to DataFrame.map so it matches Series.map. The old applymap name still works but is deprecated, so prefer df.map(func) in new code.
Q: How do I apply a function that uses multiple columns? A: Use df.apply(func, axis=1) so the function receives each row as a Series and can read several columns, for example lambda row: row['price'] * row['qty']. For performance, check first whether a direct column expression can do the same job.
Q: Why is my apply so slow? A: apply executes your function once per row or column in the Python interpreter, which cannot compete with vectorised C operations. Replace it with native arithmetic, .str/.dt accessors, np.where, or pd.cut wherever the logic allows.
Related Reading
Get The Print Version
Download a PDF of this article for offline reading.
About the Publisher
SkillVeris Team
Data Science Team
Our data team shares real-world analytics, ML, and SQL insights grounded in industry practice.
View all postsRelated Posts
Never miss an update
Get the latest tutorials and guides delivered to your inbox.
No spam. Unsubscribe anytime.