Skip to content

KeyError: None of [...] are in the [columns]

Have you asked for columns that you are certain exist?

sales[['profit', 'margin']]
KeyError: "None of [Index(['profit', 'margin'], dtype='str')] are in the [columns]"

Pandas has two messages here, and which one you get is a clue. If none of the requested columns exist you get the one above. If some exist, it names only the missing ones:

sales[['revenue', 'profit']]
KeyError: "['profit'] not in index"

So the first message means the whole list missed, which usually points at a different frame than you think you have, or at a selection made before a rename. The second means a genuine typo in one name.

Look at the names as data

The fastest way to settle it is to stop reading the names and start comparing them:

sales.columns.tolist()

Printing the list rather than the frame shows what is really there, including the things a rendered table hides. Three suspects account for most of these errors:

Stripping whitespace at load time costs one line and removes the whole class:

df.columns = df.columns.str.strip()

For the byte-order mark specifically, read_csv(..., encoding='utf-8-sig') handles it properly.

The MultiIndex version

If the frame came out of a groupby().agg() with more than one aggregation, or a pivot_table, the columns may be tuples rather than strings:

sales.columns.tolist()

Seeing [('revenue', 'sum'), ('revenue', 'mean')] explains everything: sales['revenue'] returns the group, and sales[('revenue', 'sum')] returns the column. Flattening after the aggregation is usually kinder to the code that follows, and named aggregation avoids the MultiIndex entirely:

sales.groupby('region').agg(total=('revenue', 'sum'),
                            average=('revenue', 'mean'))

The mistakes I see most often

Selecting with one set of brackets when you meant two. sales['revenue', 'profit'] is a tuple key, not a list of columns, and produces a confusing message of its own.

Assuming an inplace rename happened. rename returns a new frame unless told otherwise, so a selection written against the new names fails against the old ones.

Chasing the column when the frame is wrong. If the message lists every column you asked for, check which frame you are holding before checking the spelling.

Practice

See loc in Pandas for label-based selection, and rename in Pandas for cleaning up column names.