pandas
python
data analysis
dataframe
column comparison

Find the max of two or more columns with pandas

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In pandas, the usual way to find the maximum across two or more columns is to select those columns and call .max(axis=1). That gives you the row-wise maximum. There are also useful variations when you only have two columns, need the column name of the winner, or want special handling for missing values.

The Standard Row-Wise Maximum

Suppose you have a DataFrame like this:

python
1import pandas as pd
2
3df = pd.DataFrame({
4    "math": [80, 92, 75],
5    "science": [85, 88, 91],
6    "history": [78, 95, 89],
7})
8
9df["best_score"] = df[["math", "science", "history"]].max(axis=1)
10print(df)

Output:

text
1   math  science  history  best_score
20    80       85       78          85
31    92       88       95          95
42    75       91       89          91

The important part is axis=1, which tells pandas to compare across columns for each row.

Finding the Maximum of Exactly Two Columns

If you only have two columns and want an explicit pairwise comparison, NumPy can be handy:

python
1import numpy as np
2import pandas as pd
3
4df = pd.DataFrame({
5    "a": [1, 7, 3],
6    "b": [4, 2, 9],
7})
8
9df["max_ab"] = np.maximum(df["a"], df["b"])
10print(df)

This is fast and clear for two-column comparisons, but .max(axis=1) scales more naturally when the number of columns grows.

Getting the Column Name of the Maximum

Sometimes you need to know not only the maximum value but also which column produced it. Use .idxmax(axis=1) for that.

python
1import pandas as pd
2
3df = pd.DataFrame({
4    "math": [80, 92, 75],
5    "science": [85, 88, 91],
6    "history": [78, 95, 89],
7})
8
9df["best_subject"] = df[["math", "science", "history"]].idxmax(axis=1)
10df["best_score"] = df[["math", "science", "history"]].max(axis=1)
11
12print(df)

This is a very common pattern in reporting and feature engineering.

Handling Missing Values

By default, pandas skips NaN values when possible:

python
1import pandas as pd
2import numpy as np
3
4df = pd.DataFrame({
5    "x": [1, np.nan, 5],
6    "y": [3, 2, np.nan],
7    "z": [2, 4, 1],
8})
9
10df["row_max"] = df[["x", "y", "z"]].max(axis=1)
11print(df)

If a row has at least one real value, pandas returns the maximum of the available values. If all selected columns are missing in a row, the result is NaN.

This default is usually what you want, but it is worth knowing because missing-data behavior affects downstream analysis.

Dynamic Column Lists

In real code, the columns are often not hard-coded. You can build the list dynamically and still use the same pattern.

python
score_columns = [col for col in df.columns if col.startswith("score_")]
df["best_score"] = df[score_columns].max(axis=1)

This is useful in pipelines where the number of compared columns changes over time.

Avoid apply Unless You Need Custom Logic

You can write:

python
df["best_score"] = df[["math", "science", "history"]].apply(max, axis=1)

but .max(axis=1) is usually better. It is clearer, more idiomatic, and typically faster because it uses vectorized pandas logic instead of row-wise Python callbacks.

Reach for apply only when the rule is more complex than a straightforward maximum.

Example with a Custom Rule

If your logic is "take the max, but ignore negative values," then apply or preprocessing may make sense.

python
1import pandas as pd
2
3df = pd.DataFrame({
4    "a": [3, -1, 5],
5    "b": [4, 2, -2],
6    "c": [1, 6, 0],
7})
8
9def non_negative_max(row):
10    values = [value for value in row if value >= 0]
11    return max(values) if values else None
12
13df["custom_max"] = df[["a", "b", "c"]].apply(non_negative_max, axis=1)
14print(df)

That kind of rule is where apply becomes justified.

Common Pitfalls

One common mistake is forgetting axis=1. Without it, .max() computes the maximum down each column instead of across columns per row.

Another issue is mixing non-numeric columns into the selection accidentally. Pandas may still attempt the operation, but the results can become confusing or error-prone depending on the data types involved.

Developers also sometimes use apply(max, axis=1) for simple cases where .max(axis=1) is cleaner and faster.

Finally, if you need the name of the winning column, remember that .max(axis=1) gives the value, while .idxmax(axis=1) gives the column label. They solve related but different problems.

Summary

  • Use df[columns].max(axis=1) for the row-wise maximum across two or more columns.
  • Use np.maximum when you only need a fast pairwise maximum of two columns.
  • Use .idxmax(axis=1) when you need the column name of the maximum value.
  • 'NaN values are skipped by default when possible.'
  • Prefer vectorized pandas methods over apply unless the rule requires custom row logic.

Course illustration
Course illustration

All Rights Reserved.