Skip to content

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

Learn how to resolve the Pandas SpecificationError when using deprecated nested renamer syntax in .agg() and implement the modern keyword argument approach for named aggregations.

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 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],
})

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],
})

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'
)

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.4

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],
})

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.2

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 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_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.

Navigation