Understanding the axis Argument in Pandas – axis=0 vs axis=1 Explained 2026

Data Manipulation Mar 18, 2026

Understanding the axis Argument in Pandas – axis=0 vs axis=1 Explained 2026

The axis parameter is one of the most important and frequently misunderstood concepts in Pandas. Mastering axis=0 (rows) versus axis=1 (columns) is essential for effective data manipulation.

TL;DR — axis Explained Simply

  • axis=0 → Operate down the rows (column-wise operation)
  • axis=1 → Operate across the columns (row-wise operation)
  • Think: "0 = vertical (like the y-axis in math), 1 = horizontal"

1. Basic Examples of axis

import pandas as pd

# Create a small demo file so this example runs as-is
# (in your project, sales_data.csv is your real export)
import numpy as np
rng = np.random.default_rng(42)
n = 60
pd.DataFrame({
    "order_date": pd.date_range("2026-01-01", periods=n, freq="3D"),
    "customer_id": rng.integers(101, 121, n),
    "customer_name": rng.choice([" ana", "ben ", "chen", "dana"], n),
    "product_id": rng.integers(1, 9, n),
    "region": rng.choice(["North", "South", "East", "West"], n),
    "category": rng.choice(["Electronics", "Computers", "Books", "Home"], n),
    "payment_method": rng.choice(["card", "cash", "wallet"], n),
    "segment": rng.choice(["consumer", "business"], n),
    "quantity": rng.integers(1, 6, n),
    "amount": rng.uniform(50, 2500, n).round(2),
    "discount": rng.choice([0.0, 0.05, 0.1, 0.2], n),
}).assign(
    price=lambda d: (d["amount"] / d["quantity"]).round(2),
    profit=lambda d: (d["amount"] * rng.uniform(0.05, 0.3, n)).round(2),
).assign(
    ship_date=lambda d: d["order_date"] + pd.Timedelta(days=2),
    status=lambda d: np.where(d["amount"] > 2000, "priority", "standard"),
).to_csv("sales_data.csv", index=False)

df = pd.read_csv("sales_data.csv")

# numeric_only=True: pandas 3 no longer skips text columns silently
# axis=0 → along rows (default for most operations)
column_sums = df.sum(axis=0, numeric_only=True)        # Sum of each column
column_means = df.mean(axis=0, numeric_only=True)

# axis=1 → along columns
row_sums = df.sum(axis=1, numeric_only=True)           # Sum of each row
row_means = df.mean(axis=1, numeric_only=True)

2. Common Operations with axis

# Drop rows with missing values
df_clean = df.dropna(axis=0)        # Drop rows (default)

# Drop columns with missing values
df_clean = df.dropna(axis=1)        # Drop columns

# Mean of each column
col_means = df.mean(axis=0, numeric_only=True)

# Mean of each row
row_means = df.mean(axis=1, numeric_only=True)

# Fill missing values column-wise
df.fillna(df.mean(axis=0, numeric_only=True), axis=0)   # Fill with column mean

3. Real-World Example with groupby + axis

# Sum sales by region (group along rows)
sales_by_region = df.groupby("region")["amount"].sum()

# Calculate percentage of total for each row
df["percentage"] = df["amount"] / df["amount"].sum(axis=0) * 100

# Normalize each row (row-wise operation)
df_normalized = df[["amount", "quantity"]].div(
    df[["amount", "quantity"]].sum(axis=1), 
    axis=0
)

4. Best Practices in 2026

  • Use axis=0 when you want to operate per column (most common)
  • Use axis=1 when you want to operate per row
  • Always be explicit with axis instead of relying on default behavior
  • When in doubt, remember: axis=0 affects rows (vertical), axis=1 affects columns (horizontal)
  • Use meaningful variable names to avoid confusion when using axis=1

What the Axis Argument Means

axis tells pandas the direction in which an operation runs. axis=0, or axis="index", works down the rows and produces one result per column. axis=1, or axis="columns", works across the columns and produces one result per row.

A helpful rule is that the axis you name is the one that collapses. df.sum(axis=0) collapses the rows, while df.drop("col", axis=1) removes something along the columns. In pandas 3, summaries on mixed tables need numeric_only=True to skip text columns.

Worked Example: Totals per Column and per Row

Student scores are summed and averaged in both directions to show the difference.

import pandas as pd

df = pd.DataFrame({
    "name": ["Ana", "Ben", "Cara"],
    "math": [80, 90, 70],
    "science": [85, 75, 95],
})

print(df.sum(axis=0, numeric_only=True))
print(df.mean(axis="columns", numeric_only=True))

df["total"] = df[["math", "science"]].sum(axis=1)
print(df.drop("name", axis=1))

axis=0 returns one total per subject, while axis=1 gives each student an average or total. Selecting the numeric columns explicitly before a row-wise sum keeps the result easy to reason about.

Common Mistakes

  • Swapping axis=0 and axis=1 and getting the wrong shape.
  • Summing mixed text and number columns without numeric_only=True.
  • Forgetting axis=1 when dropping a column with drop().
  • Using row-wise apply where a vectorised axis=1 method exists.

Quick Summary

  • axis=0 works down rows: one result per column.
  • axis=1 works across columns: one result per row.
  • Named forms "index" and "columns" improve readability.
  • Use numeric_only=True for mixed DataFrames.

Conclusion

The axis argument is fundamental to understanding how Pandas operations work. In 2026, always be explicit with axis=0 (operate down columns) and axis=1 (operate across rows). Mastering this concept will eliminate many common bugs and make your data manipulation code much more predictable and professional.

Next steps:

  • Review your current Pandas code and make sure you are using axis explicitly and correctly in all sum(), mean(), dropna(), and fillna() operations

Related Tutorials

Share:
Last updated: March 2026
Built-in Functions in Python 2026 str() in Python 2026: String Conversion + Modern Formatting & Best Practices memoryview with JAX in Python 2026: Zero-Copy NumPy → JAX Array Interop + Efficient ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + GPU Pinning & ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + ML Examples memoryview with NumPy & PyTorch in Python 2026: Zero-Copy Views, Efficient Slicing & ML Interop Examples memoryview with NumPy in Python 2026: Zero-Copy Views, Efficient Slicing & Real ML Examples memoryview() in Python 2026: Zero-Copy Magic for Large Binary Data + Real Examples import() in Python 2026: How It Works, Security Risks & Modern Alternatives (importlib) zip() in Python 2026: How to Use It, strict=True Behavior & Real-World Examples vars() in Python 2026: Accessing Object Namespace + Modern Introspection Patterns type() in Python 2026: Dynamic Type Inspection & Object Creation + Modern Patterns tuple() in Python 2026: Immutable Sequences + Modern Patterns & Best Practices super() in Python 2026: Method Resolution & Modern Inheritance Patterns sum() in Python 2026: Summing Iterables + Modern Numeric Patterns & Best Practices staticmethod() in Python 2026: Static Methods, Utility Functions & Modern Best Practices sorted() in Python 2026: Sorting Iterables + Modern Patterns & Best Practices slice() in Python 2026: Creating Slice Objects + Modern Patterns & Best Practices setattr() in Python 2026: Dynamic Attribute Setting + Modern Patterns & Safety set() in Python 2026: Mutable Sets Creation + Modern Patterns & Best Practices