Reputation: 568
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
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
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