Multiple Summaries in Pandas – Advanced Aggregation Techniques 2026

Data Manipulation Mar 18, 2026

Multiple Summaries in Pandas – Advanced Aggregation Techniques 2026

When you need several different summary statistics across multiple columns, Pandas offers powerful and flexible ways to do it cleanly. In 2026, the combination of .agg(), named aggregations, and method chaining is the recommended approach for creating professional multi-summary reports.

TL;DR — Best Patterns for Multiple Summaries

  • Use dictionary-style .agg() for different functions per column
  • Use named aggregation syntax for clean, meaningful column names
  • Combine with groupby() for segmented multi-summaries
  • Use custom functions when built-in ones are not enough

1. Basic Multiple Summaries on Single DataFrame

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"])

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

print(multi_summary)

2. Grouped Multiple Summaries (Most Useful Pattern)

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

# Clean column names
result.columns = [
    "total_sales", "avg_sale", "order_count", "sales_std",
    "total_quantity", "avg_quantity", "unique_customers", "unique_products"
]

print(result)

3. Named Aggregation – Cleanest & Most Recommended in 2026

monthly_report = (
    df
    .groupby(["region", df["order_date"].dt.to_period("M")])
    .agg(
        total_sales=("amount", "sum"),
        average_sale=("amount", "mean"),
        order_count=("amount", "count"),
        total_quantity=("quantity", "sum"),
        unique_customers=("customer_id", "nunique"),
        sales_volatility=("amount", "std")
    )
    .round(2)
    .reset_index()
)

print(monthly_report)

4. Using Custom Functions for Multiple Summaries

def coefficient_of_variation(x):
    return x.std() / x.mean() if x.mean() != 0 else 0

summary = (
    df
    .groupby("region")
    .agg(
        total_revenue=("amount", "sum"),
        avg_order_value=("amount", "mean"),
        cv=("amount", coefficient_of_variation),
        customer_diversity=("customer_id", "nunique")
    )
    .round(2)
)

Best Practices in 2026

  • Prefer named aggregation syntax for readable and maintainable code
  • Use method chaining to keep your aggregation logic clean
  • Always round final results for professional-looking reports
  • Define small custom functions when you need special calculations
  • Use .reset_index() when you want a flat table for further processing or export

Choosing the Right Statistics

Multiple summaries are useful only when each number adds information. A good default set is count, sum, mean and median: the count shows how much data stands behind the other numbers, the sum gives the total, and comparing mean with median reveals skew. If the mean is far above the median, a few large values are pulling it up, and the median is the better "typical" value.

Add min, max or std when you need to see spread, but avoid long lists of statistics that nobody reads.

Worked Example: Spotting Skew with Mean and Median

This example shows how two statistics together tell a story that one alone hides.

import pandas as pd

df = pd.DataFrame({
    "channel": ["web"] * 5 + ["shop"] * 5,
    "amount": [20, 25, 30, 22, 900, 40, 45, 50, 42, 48],
})

stats = df.groupby("channel")["amount"].agg(["count", "mean", "median", "max"])
print(stats)
#          count   mean  median  max
# channel
# shop         5   45.0    45.0   50
# web          5  199.4    25.0  900

The web channel looks far stronger by mean, but its median shows that a single 900 order creates the difference. Reporting both protects you from a misleading conclusion.

Common Mistakes

  • Reporting the mean alone: one outlier can dominate it
  • Ignoring the count: a mean of three rows is much less reliable than a mean of three thousand
  • Rounding too early: round only the final table for display
  • Stacking too many metrics: wide tables hide the few numbers that matter

Quick Summary

  • Pair the mean with the median to see skew
  • Always include a count
  • Use a list or named aggregation to calculate everything in one call

Conclusion

Creating multiple summaries across several columns is a daily task in data manipulation. In 2026, using Pandas .agg() with named aggregation gives you the perfect balance of power, readability, and performance. Master this pattern and your summary reports will be both insightful and professionally formatted.

Next steps:

  • Take one of your existing 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