Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pandas: Swap rows between columns

Some rows were input in the wrong columns so now I need to swap them.

df = pd.DataFrame({'c': {0: '22:58:00', 1: '23:03:00', 2: '0', 3: '10'}, 'a': {0: '0', 1: '10', 2: '22:58:00', 3: '23:03:00'}, 'd': {0: '23:27:00', 1: '23:39:00', 2: '10', 3: '17'}, 'b': {0: '10', 1: '17', 2: '23:27:00', 3: '23:39:00'}})

          a         b         c         d
0         0        10  22:58:00  23:27:00
1        10        17  23:03:00  23:39:00
2  22:58:00  23:27:00         0        10
3  23:03:00  23:39:00        10        17

My current approach

cpy = df[['a', 'b']]
df.loc[2:, 'a'] = df['c']
df.loc[2:, 'b'] = df['d']
df.loc[2:, 'c'] = cpy['a']
df.loc[2:, 'd'] = cpy['b']

Expected output

    a   b         c         d
0   0  10  22:58:00  23:27:00
1  10  17  23:03:00  23:39:00
2   0  10  22:58:00  23:27:00
3  10  17  23:03:00  23:39:00

It works but this is only possible because it was 4 columns. Is there a better way to do this?

Note the dtypes can cause issues with sorting df.loc[0]['c'] is datetime.time(22, 58)

Maybe there is something like

df.swap_row_col(index=[2:], columns_from=['a', 'b'], columns_to=['c', 'd'])

like image 428
Kenan Avatar asked Dec 08 '25 01:12

Kenan


2 Answers

Maybe we can try notice here in my solution if the original order is 100, 0 my out put still 100, 0

df=pd.DataFrame(df.apply(lambda x : sorted(x,key= lambda s: ':' in s),1).tolist(),columns=df.columns)
Out[119]: 
     c   a         d         b
0    0  10  22:58:00  23:27:00
1   10  17  23:03:00  23:39:00
2  100  10  22:58:00  23:27:00
3   10  17  23:03:00  23:39:00
like image 143
BENY Avatar answered Dec 10 '25 14:12

BENY


Method 1: np.sort

np.sort with pd.DataFrame constructor works for me:

df = pd.DataFrame(np.sort(df.astype(str)), columns=df.columns)

    a   b         c         d
0   0  10  22:58:00  23:27:00
1  10  17  23:03:00  23:39:00
2   0  10  22:58:00  23:27:00
3  10  17  23:03:00  23:39:00

Method 2:

More general, by checking which rows match to your date pattern and vice versa and then swapping these values with bfill or ffill:

match_pattern = df.apply(lambda x: x.str.match('\d{2}:\d{2}:\d{2}'))

numeric = df.where(~match_pattern).bfill(axis=1).dropna(how='any', axis=1)
dates = df.where(match_pattern).ffill(axis=1).dropna(how='any', axis=1)

df = pd.concat([numeric, dates], axis=1)

    a   b         c         d
0   0  10  22:58:00  23:27:00
1  10  17  23:03:00  23:39:00
2   0   0  23:27:00  23:27:00
3  10  10  23:39:00  23:39:00
like image 36
Erfan Avatar answered Dec 10 '25 14:12

Erfan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!