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 resultView on GitHub (pinned to 71959b8cb9)
Solutions
- Make all dict values produce the same kind of output: either all aggregations (scalars/lists of scalars) or all transforms (same-shaped NDFrame).
- Split into two `agg`/`transform` calls and concatenate manually.
- 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
- Audit each dict value to ensure it returns either all scalars or all NDFrame-shaped results.
- Split into separate agg/transform calls when in doubt.
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
- cannot combine transform and aggregation operations
- invalid value for result_type, must be one of {None, 'reduce
- Operation {func} does not support axis=1
- nested renamer is not supported
- Label(s) {list(cols)} do not exist
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/c28fd4be7f6bf5d9.
Report an issue: GitHub.