Tomasz
Tomasz

Reputation: 568

Swap or exchange column names in pandas dataframe with multiple columns

I would like to swap (exchange) only column names in pandas, preferably with one-liner. The additional problem is the fact that I have about 100 columns, which causes that I can't reassign all column names, so I would like to replace pairs of selected column names. I don't know the indexes of columns (it will vary), so I must use column names.

I tried following code:

import pandas as pd

probes = {'Spam': [0.0,1.0],
        'Ham': [1.0,0.0],
        'PT011': [0.11,0.21],
        'PT012': [0.12,0.22],
        'PT021': [0.21,0.11],
        'PT022': [0.22,0.12]}

df = pd.DataFrame(probes,columns= ['Spam','Ham','PT011', 'PT012','PT021','PT022'])
print("Before renaming:\n",df)
df.rename(columns={'PT011':'PT021', 'PT012':'PT022','PT021':'PT011','PT022':'PT012'}, inplace=True)
print("After renaming:\n",df)

And I got:

Before renaming:
    Spam  Ham  PT011  PT012  PT021  PT022
0   0.0  1.0   0.11   0.12   0.21   0.22
1   1.0  0.0   0.21   0.22   0.11   0.12
After renaming:
    Spam  Ham  PT021  PT022  PT011  PT012
0   0.0  1.0   0.11   0.12   0.21   0.22
1   1.0  0.0   0.21   0.22   0.11   0.12

But I would expect some simply one-liner to work allowing to swap column names, with no necessity to define both pairs of column names to swap, but to define only one pair of column names, retaining data, with some loc or iloc attribute, like:

df['PT011','PT012']=df['PT021','PT022']

with expected output (also proposed order is desired):

   Spam  Ham   PT011  PT012  PT021  PT022
0   0.0  1.0   0.21   0.22   0.11   0.12
1   1.0  0.0   0.11   0.12   0.21   0.22

The answers shown in: Renaming columns in pandas, in example:

df.columns = df.columns.str.replace('PT011','PT021')

is not suitable for my case, because it still needs to give both pairs of column names or needs to reassign names of all columns and doesn't give desired order of columns.

Upvotes: 4

Views: 9109

Answers (2)

Tomasz
Tomasz

Reputation: 568

I the pandas documentation: Indexing and selecting data I found an easy and simple approach to do this:

df[['PT011','PT021']]=df[['PT021','PT011']]
df[['PT012','PT022']]=df[['PT022','PT012']]

which gives output in desired order:

After renaming:
    Spam  Ham  PT011  PT012  PT021  PT022
0   0.0  1.0   0.21   0.22   0.11   0.12
1   1.0  0.0   0.11   0.12   0.21   0.22

Upvotes: 8

CJR
CJR

Reputation: 3985

If you have a dict that you can use to map stuff then this works fine.

df_map = {'PT011':'PT021', 'PT012':'PT022'}
df.columns = [{**df_map, **{v:k for k,v in df_map.items()}}.get(x, x) for x in df.columns]

>>> df
   Spam  Ham  PT021  PT022  PT011  PT012
0   0.0  1.0   0.11   0.12   0.21   0.22
1   1.0  0.0   0.21   0.22   0.11   0.12

Or you could use rename() to be safer.

df.rename(columns={**df_map, **{v:k for k,v in df_map.items()}}, inplace=True)

I'm not sure what you mean when you say you don't want to give it two names to flip. How would you know which columns to swap otherwise?

As for your followup question:

df_map = {'PT011':'PT021', 'PT012':'PT022'}
df_column_order = df.columns.tolist()
df.rename(columns={**df_map, **{v:k for k,v in df_map.items()}}, inplace=True)
df = df.reindex(df_column_order, axis=1)

Upvotes: 4

Related Questions