Skip to main content

Pandas: How to Fix "SpecificationError: nested renamer is not supported"

The pandas.errors.SpecificationError: nested renamer is not supported error in Pandas typically arises when using an older, now deprecated syntax for the .agg() (aggregate) method, especially when trying to apply multiple aggregation functions and rename the resulting columns simultaneously with a nested dictionary structure.

This guide explains the error and demonstrates the modern, correct syntax to achieve the desired aggregations and column naming.

Understanding the Error: Deprecated Syntax

In older versions of Pandas, one way to apply multiple aggregation functions to a Series or DataFrame and name the output columns was by passing a dictionary where keys were the new column names and values were lists of functions. This "nested renamer" syntax is no longer supported.

import pandas as pd

df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Carl', 'Dan'],
'salary': [175.1, 180.2, 190.3, 205.4],
})

try:
# ⛔️ Deprecated syntax causing the error
series_agg = df['salary'].agg({'min_salary': ['min'], 'max_salary': ['max']})
# Or another common deprecated form for a single column:
# series_agg = df['salary'].agg({'salary': ['min', 'max']})
print(series_agg)
except pd.errors.SpecificationError as e:
print(f"Error: {e}")

Output:

Error: nested renamer is not supported

In the example above, the attempt to use a dictionary like {'salary': ['min', 'max']} or {'new_name': ['func']} where the value is a list of functions directly within the agg call on a Series is what triggers this specific error in modern Pandas versions.

The Solution: Using Keyword Arguments with .agg()

The current and recommended way to achieve named aggregations is to pass keyword arguments to the .agg() method. Each keyword argument defines a new column name for the result, and its value is the aggregation function to apply (as a string or a callable).

import pandas as pd

df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Carl', 'Dan'],
'salary': [175.1, 180.2, 190.3, 205.4],
})

# ✅ Correct syntax: using keyword arguments
series_agg_kw = df['salary'].agg(
custom_min_salary_name='min',
custom_max_salary_name='max',
average_salary='mean'
)

print(series_agg_kw)
print(f"Min salary: {series_agg_kw['custom_min_salary_name']}")

Output:

custom_min_salary_name    175.10
custom_max_salary_name 205.40
average_salary 187.75
Name: salary, dtype: float64
Min salary: 175.1

Here, custom_min_salary_name becomes the name for the result of the 'min' aggregation, and so on. This syntax is clear, flexible, and fully supported.

Applying the Solution to GroupBy.agg()

The same keyword argument syntax works perfectly when performing aggregations on a GroupBy object.

import pandas as pd

df = pd.DataFrame({
'department': ['HR', 'HR', 'IT', 'IT', 'Sales', 'Sales'],
'salary': [175.1, 205.1, 180.2, 350.2, 190.3, 500.1],
})

# ✅ Correct syntax for GroupBy.agg()
grouped_agg = df.groupby('department')['salary'].agg(
minimum_salary='min',
maximum_salary='max',
average_salary='mean'
)

print(grouped_agg)

Output:

            minimum_salary  maximum_salary  average_salary
department
HR 175.1 205.1 190.1
IT 180.2 350.2 265.2
Sales 190.3 500.1 345.2

Converting Aggregation Results to a DataFrame

When you aggregate a single Series (like df['salary'].agg(...)), the result is a Pandas Series. If you need a DataFrame, you can wrap the result with pd.DataFrame().

import pandas as pd

df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Carl', 'Dan'],
'salary': [175.1, 180.2, 190.3, 205.4],
})

series_agg_kw = df['salary'].agg(
min_sal='min',
max_sal='max'
)

# Convert the resulting Series to a DataFrame
df_agg_result = pd.DataFrame(series_agg_kw)
print(df_agg_result)
print()

# Often, you might want the new names as columns, not index.
# For a DataFrame with new names as columns, a common pattern is:
df_agg_result_cols = pd.DataFrame([series_agg_kw]) # Wrap in a list
print("DataFrame with named aggregations as columns:")
print(df_agg_result_cols)

Output:

         salary
min_sal 175.1
max_sal 205.4

DataFrame with named aggregations as columns:
min_sal max_sal
salary 175.1 205.4
note

When aggregating a GroupBy object, the result is typically already a DataFrame if multiple aggregations are performed or if aggregating multiple columns.

Alternative: Passing a List of Functions and Renaming

While keyword arguments are preferred for simultaneous aggregation and renaming, you can pass a list of function names (as strings) to .agg(). This will generate columns named after the functions. You can then rename these columns if needed.

import pandas as pd

df = pd.DataFrame({
'department': ['HR', 'HR', 'IT', 'IT'],
'salary': [175.1, 205.1, 180.2, 350.2],
})

# Step 1: Aggregate with a list of functions
grouped_list_agg = df.groupby('department')['salary'].agg(['min', 'max', 'mean'])
print("Result with default column names:")
print(grouped_list_agg)
print()

# Step 2: Rename columns
grouped_list_agg.columns = ['min_salary', 'max_salary', 'avg_salary']
print("Result after renaming columns:")
print(grouped_list_agg)

Output:

Result with default column names:
min max mean
department
HR 175.1 205.1 190.1
IT 180.2 350.2 265.2

Result after renaming columns:
min_salary max_salary avg_salary
department
HR 175.1 205.1 190.1
IT 180.2 350.2 265.2
note

This approach is valid but involves an extra step for renaming compared to the direct keyword argument method.

If you are applying aggregations to a GroupBy object without selecting a specific column first (i.e., applying to all numeric columns), and you pass a list with duplicate function names, you'll get a SpecificationError: Function names must be unique if there is no new column names assigned.

import pandas as pd

df = pd.DataFrame({
'department': ['HR', 'HR', 'IT', 'IT'],
'salary': [175.1, 205.1, 180.2, 350.2],
'bonus': [10, 12, 15, 20]
})

try:
# ⛔️ Error: Applying to all numeric columns with duplicate function 'min'
# (Note: 'mean' also applies to all, this error is about the list itself)
error_df = df.groupby('department').agg(['min', 'max', 'min'])
print(error_df)
except pd.errors.SpecificationError as e:
print(f"Error: {e}")
# Output: Error: Function names must be unique if there is no new column names assigned

Output:

Error: Function names must be unique if there is no new column names assigned

Solution:

  • Select specific columns before agg: df.groupby('department')['salary'].agg(['min', 'max', 'min']) (this would create three columns for 'salary': min, max, min).
  • Use the keyword argument syntax to provide unique names: df.groupby('department').agg(min_val_1='min', max_val='max', min_val_2='min').
  • Ensure your list of functions does not have duplicates if applying to multiple columns by default: df.groupby('department').agg(['min', 'max', 'median']).

Important Note: Ensure Columns Exist for Dictionary-Based Aggregation

While the "nested renamer" error is about the structure of the dictionary, if you use the valid dictionary syntax for applying different aggregations to different columns on a DataFrame.agg() or GroupBy.agg() (not a Series), ensure the column keys in your dictionary actually exist.

import pandas as pd

df = pd.DataFrame({
'name': ['Alice', 'Bob'],
'salary': [175.1, 180.2],
'age': [30, 40]
})

# ✅ Valid dictionary syntax for DataFrame.agg
valid_agg = df.agg({'salary': 'sum', 'age': 'mean'})
print("Valid aggregation:")
print(valid_agg)

try:
# ⛔️ KeyError: 'experience' (not SpecificationError, but related to dict keys)
invalid_col_agg = df.agg({'salary': 'sum', 'experience': 'mean'})
print(invalid_col_agg)
except KeyError as e:
print(f"Error: Column {e} not found.")

Output:

Valid aggregation:
salary 355.3
age 35.0
dtype: float64
Error: Column "Column(s) ['experience'] do not exist" not found.

Conclusion

The pandas.errors.SpecificationError: nested renamer is not supported arises from using an outdated dictionary syntax with nested lists for function names in the .agg() method.

The modern and correct way to perform named aggregations is by passing keyword arguments to .agg(), where each argument is new_column_name='aggregation_function'. This applies to aggregations on both Series and GroupBy objects. Understanding this syntax will help you write cleaner and more maintainable Pandas code.