0

I have a dataframe df1 with two columns: CODE & RANK

     CODE RANK
100  12   1
212  6    2
358  4    3
342  10   4
111  8    5

My dataframe is ordered by Rank. I don't want to change completely the sorting rule but want to move to head some rows generated by a filter:

  df1[df1['RANK'] >= 4]]

The result should then be:

     CODE RANK
342  10   4
111  8    5
100  12   1
212  6    2
358  4    3

Do you know how I can do it properly?

Thanks for help

ImFabien75
  • 157
  • 1
  • 9

3 Answers3

2

You can use pd.concat:

df2 = pd.concat([df1[df1['RANK'] >= 4], df1[df1['RANK'] < 4]])

Output:

CODE    RANK
10      4
8       5
12      1
6       2
4       3

Or faster way as suggested by @mozway:

m = df1['RANK'] >= 4
df2 = pd.concat([df1[m], df1[~m]])
Mattravel
  • 1,358
  • 1
  • 15
  • 1
    Note that `≥4` and `<4` are mutually exclusive and complementary (except for NaNs), so you can compute only one mask `m = df1['RANK'] >= 4` then `pd.concat([df1[m], df1[~m]])` ;) – mozway Feb 28 '23 at 10:55
1

Use sort_values with a custom key and stable sorting:

df.sort_values(by='RANK', key=lambda s: s.lt(4), kind='stable')

# or
# df.sort_values(by='RANK', key=lambda s: s.ge(4), ascending=False, kind='stable')

Output:

     CODE  RANK
342    10     4
111     8     5
100    12     1
212     6     2
358     4     3

How it works: when passing the key, a boolean Series is created with True/False values. True is seen as 1 and is sorted after False (equivalent to 0).

df['RANK'].lt(4)
100     True      # sorted after False
212     True
358     True
342    False
111    False
Name: RANK, dtype: bool
mozway
  • 194,879
  • 13
  • 39
  • 75
0

Use DataFrame.sort_values with key and kind parameters, because default sorting algo is quicksort, see also what is stability in sorting algorithms and why is it important:

df1 = df.sort_values('RANK', key=lambda x: x >= 4, ascending=False, kind='stable')
#alternative solution
#df1 = df.sort_values('RANK', key=lambda x: x < 4, kind='stable')
print (df1)
     CODE  RANK
342    10     4
111     8     5
100    12     1
212     6     2
358     4     3
jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252