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:
series_agg = df['salary'].agg({'min_salary': ['min'], 'max_salary': ['max']})
print(series_agg)
except pd.errors.SpecificationError as e:
print(f"Error: {e}") Output:
Error: nested renamer is not supportedIn 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],
})
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.1Here, 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],
})
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.2Converting 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'
)
df_agg_result = pd.DataFrame(series_agg_kw)
print(df_agg_result)
print()
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.4Alternative: 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],
})
grouped_list_agg = df.groupby('department')['salary'].agg(['min', 'max', 'mean'])
print("Result with default column names:")
print(grouped_list_agg)
print()
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.2Related SpecificationError: Duplicate Function Names
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_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 assignedSolution:
- 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_agg = df.agg({'salary': 'sum', 'age': 'mean'})
print("Valid aggregation:")
print(valid_agg)
try:
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.