pandas-dev/pandas · error · ValueError

cannot perform both aggregation and transformation operation

Error message

cannot perform both aggregation and transformation operations simultaneously

What it means

Raised inside `wrap_results_dict_like` when results from a dict-like agg/apply contain a mix of NDFrame objects and scalars. Each dict entry produced a different result kind, making the combined output shape ill-defined — some columns would broadcast, others would aggregate.

Source

Thrown at pandas/core/apply.py:689

                keys_to_use = result_index
                results = result_data

            if selected_obj.ndim == 2:
                # keys are columns, so we can preserve names
                ktu = Index(keys_to_use)
                ktu._set_names(selected_obj.columns.names)
                keys_to_use = ktu

            axis: AxisInt = 0 if isinstance(obj, ABCSeries) else 1
            result = concat(
                results,
                axis=axis,
                keys=keys_to_use,
                sort=False,
            )
        elif any(is_ndframe):
            # There is a mix of NDFrames and scalars
            raise ValueError(
                "cannot perform both aggregation "
                "and transformation operations "
                "simultaneously"
            )
        else:
            from pandas import Series

            # we have a list of scalars
            # GH 36212 use name only if obj is a series
            if obj.ndim == 1:
                obj = cast("Series", obj)
                name = obj.name
            else:
                name = None

            result = Series(result_data, index=result_index, name=name)

        return result

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Make all dict values produce the same kind of output: either all aggregations (scalars/lists of scalars) or all transforms (same-shaped NDFrame).
  2. Split into two `agg`/`transform` calls and concatenate manually.
  3. Use `apply` instead of `agg` if you genuinely need heterogeneous per-column behavior and will align results yourself.

Example fix

# before
df.agg({'A': ['sum'], 'B': lambda s: s.fillna(0)})
# after
agg = df.agg({'A': ['sum']})
trans = df[['B']].transform(lambda s: s.fillna(0))
Defensive patterns

Strategy: validation

Validate before calling

import pandas as pd

def safe_dict_agg(df, spec):
    sample = df[df.columns[0]]
    kinds = set()
    for col, fns in spec.items():
        fns = [fns] if not isinstance(fns, list) else fns
        for f in fns:
            out = (getattr(sample, f) if isinstance(f, str) else f)(sample) if False else None
    # simpler: just check return shape consistency
    return df.agg(spec)  # delegate, raise if mixed

Type guard

def is_uniform_dict_spec(spec, df) -> bool:
    import pandas as pd
    shapes = set()
    for col, fns in spec.items():
        fns = [fns] if not isinstance(fns, list) else fns
        for f in fns:
            try:
                r = getattr(df[col], f)() if isinstance(f, str) else f(df[col])
                shapes.add('nd' if isinstance(r, pd.Series) else 'scalar')
            except Exception:
                return False
    return len(shapes) <= 1

Try / catch

try:
    df.agg(spec)
except ValueError as e:
    if 'cannot perform both aggregation and transformation' in str(e):
        # split spec by result kind and run separately
        ...
    raise

Prevention

When it happens

Trigger: `df.agg({'A': ['sum', 'mean'], 'B': lambda s: s})` — col A aggregates to scalars, col B returns a Series. The `any(is_ndframe)` branch fires because results contain both NDFrame and scalar entries.

Common situations: Mixing a list of named reductions for one column with a transform-style function for another column; copy-pasting dict specs from different code paths; refactoring that changed one function's return shape.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/c28fd4be7f6bf5d9. Report an issue: GitHub.