Summaries on Multiple Columns in Pandas – Advanced Aggregations 2026

Data Manipulation Mar 18, 2026

Summaries on Multiple Columns in Pandas – Advanced Aggregations 2026

When performing data manipulation, you often need different summary statistics for different columns at the same time. In 2026, Pandas makes this elegant and efficient using the .agg() method with multiple columns and custom functions.

TL;DR — Best Ways to Summarize Multiple Columns

  • Use dictionary syntax in .agg() for full control
  • Named aggregation syntax for clean column names
  • Combine with groupby() for segmented analysis
  • Use lambda or custom functions when needed

1. Basic Multi-Column Aggregation

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("2025-10-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", "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),
}).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", parse_dates=["order_date"])

summary = df.agg({
    "amount": ["sum", "mean", "median", "min", "max", "std"],
    "quantity": ["sum", "mean", "max"],
    "customer_id": "nunique",
    "region": "nunique"
}).round(2)

print(summary)

2. Grouped Summaries on Multiple Columns (Most Common Pattern)

result = (
    df
    .groupby(["region", df["order_date"].dt.to_period("M")])
    .agg({
        "amount": ["sum", "mean", "count"],
        "quantity": ["sum", "mean"],
        "customer_id": "nunique",
        "product_id": "nunique"
    })
    .round(2)
)

# Flatten multi-level columns
result.columns = ["total_sales", "avg_sale", "order_count", 
                  "total_quantity", "avg_quantity", "unique_customers", "unique_products"]
print(result)

3. Named Aggregation (Cleanest & Recommended in 2026)

monthly_summary = (
    df
    .groupby(["region", df["order_date"].dt.to_period("M")])
    .agg(
        total_sales=("amount", "sum"),
        avg_sale=("amount", "mean"),
        order_count=("amount", "count"),
        total_qty=("quantity", "sum"),
        unique_customers=("customer_id", "nunique")
    )
    .round(2)
    .reset_index()
)

print(monthly_summary)

4. Using Custom Functions on Multiple Columns

def range_func(x):
    return x.max() - x.min()

summary = (
    df
    .groupby("region")
    .agg(
        sales_range=("amount", range_func),
        qty_range=("quantity", range_func),
        amount_per_order=("amount", "mean")
    )
)
print(summary)

Best Practices in 2026

  • Use named aggregation syntax for readable column names
  • Always round final results for clean output
  • Combine with .reset_index() when you need flat DataFrames
  • Define small helper functions for complex calculations
  • Use method chaining for better readability

Why Summarise Several Columns Together

Real questions rarely involve one column. A sales manager wants revenue, units and order count per region at the same time, and calculating them in separate steps means separate group operations and a manual merge. pandas can compute every column in one pass, which is faster and guarantees that all numbers describe exactly the same groups.

The key decision is the output shape. A dictionary of lists gives MultiIndex columns, which are handy for exploring, while named aggregation gives one flat column per metric, which is better for reports and exports.

Worked Example: Ratios Built from Several Sums

Some metrics, like average price per unit, must be calculated from totals after grouping, not averaged row by row.

import pandas as pd

df = pd.DataFrame({
    "region": ["North", "North", "South", "South"],
    "amount": [100.0, 300.0, 50.0, 150.0],
    "quantity": [1, 5, 1, 1],
})

summary = df.groupby("region").agg(revenue=("amount", "sum"), units=("quantity", "sum"))
summary["price_per_unit"] = summary["revenue"] / summary["units"]
print(summary)
#         revenue  units  price_per_unit
# region
# North     400.0      6       66.666667
# South     200.0      2      100.000000

Averaging the row-level prices for North would give 80.0, which overweights the small order. Dividing the totals gives the true weighted value.

Common Mistakes

  • Averaging ratios: compute ratios from summed columns after the aggregation
  • Including ID columns: summing customer IDs produces meaningless numbers; select the columns you need
  • Mixing text columns into sum: string columns get concatenated or raise errors
  • Losing track of MultiIndex columns: flatten them or use named aggregation

Quick Summary

  • Aggregate many columns in one agg() call
  • Build ratios from totals, not from row averages
  • Named aggregation keeps the result flat and readable

Conclusion

Summarizing multiple columns efficiently is a core skill in Pandas data manipulation. In 2026, the combination of .agg() with named aggregation and proper grouping gives you maximum flexibility and clean, professional-looking results. Master these patterns and your summary reports will become much more insightful and maintainable.

Next steps:

  • Take one of your current groupby operations and rewrite it using named aggregation syntax

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