简体   繁体   中英

Python pandas: swap column values of a DataFrame slice

I have a DataFrame like:

df = pd.DataFrame({"type":['pet', 'toy', 'toy', 'car'], 'symbol': ['A', 'B', 'C', 'D'], 'desc': [1, 2, 3, 4]})
df
Out[22]: 
  type symbol  desc
0  pet      A     1
1  toy      B     2
2  toy      C     3
3  car      D     4

My goal is to swap the values of symbol and desc for the rows whose type is toy :

  type symbol  desc
0  pet      A     1
1  toy      2     B     # <-- B and 2 are swapped
2  toy      3     C     # <-- C and 3 are swapped
3  car      D     4

So I am going to take a slice first, then do the swap on the slice, but failed. My scripts, warnings and results are:

df[df['type']=='toy'][['symbol', 'desc']] = df[df['type']=='toy'][['desc', 'symbol']]
/anaconda3/lib/python3.8/site-packages/pandas/core/frame.py:3191: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  self[k1] = value[k2]
df
Out[31]: 
  type symbol  desc
0  pet      A     1
1  toy      B     2    # <-- didn't work  :(
2  toy      C     3
3  car      D     4

Is there any advice?

Let us do

m = df.type=='toy'
l = ['symbol','desc']
df.loc[m,l] = df.loc[m,l[::-1]].values
df
Out[89]: 
  type symbol desc
0  pet      A    1
1  toy      2    B
2  toy      3    C
3  car      D    4

Or try with rename

m = df.type=='toy'
l = ['symbol','desc']

out = pd.concat([df[~m],df[m].rename(columns=dict(zip(l,l[::-1])))]).sort_index()

Let's try something like:

import pandas as pd

df = pd.DataFrame(
    {"type": ['pet', 'toy', 'toy', 'car'], 'symbol': ['A', 'B', 'C', 'D'],
     'desc': [1, 2, 3, 4]})

m = df['type'] == 'toy'

df.loc[m, ['symbol', 'desc']] = df.loc[m, ['desc', 'symbol']].to_numpy()
print(df)

Output:

  type symbol desc
0  pet      A    1
1  toy      2    B
2  toy      3    C
3  car      D    4

Use to_numpy() / values to prevent columns from matching to their old column names.

You can also use pandas where:

df[['symbol', 'desc']] = df[['desc', 'symbol']].where(df['type'] == 'toy',
                                                      df[['symbol', 'desc']].values)

Output:

    type  symbol  desc
0    pet       A     1
1    toy       2     B
2    toy       3     C
3    car       D     4

You can also use list(zip(...)) :

m = df['type']=='toy'
df.loc[m, ['symbol', 'desc']] = list(zip(df.loc[m, 'desc'], df.loc[m, 'symbol']))

Or simply use .values :

m = df['type']=='toy'
df.loc[m, ['symbol', 'desc']] = df.loc[m, ['desc', 'symbol']].values

Result:

print(df)

  type symbol desc
0  pet      A    1
1  toy      2    B
2  toy      3    C
3  car      D    4

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM