Pandas сортирует один столбец по индивидуальному порядку, а другой — естественным образом

Рассмотрим следующий код:

import pandas
import numpy

strs = ['custom','sort']*5
df = pandas.DataFrame(
    {
        'string': strs,
        'number': numpy.random.randn(len(strs)),
    }
)

sort_string_like_this = {'sort': 0, 'custom': 1}
print(df.sort_values(['string','number'], key=lambda x: x.map(sort_string_like_this)))

который печатает

   string    number
1    sort -0.074041
3    sort  1.057676
5    sort -0.612289
7    sort  0.757922
9    sort  0.671288
0  custom -0.339373
2  custom -0.320231
4  custom -1.125380
6  custom  2.120829
8  custom -0.031580

Я хотел бы отсортировать его по столбцу string, используя индивидуальный порядок, заданный словарем, и по столбцу number, используя естественный порядок чисел. Как это можно сделать?

🤔 А знаете ли вы, что...
Python подходит для начинающих программистов благодаря своей простоте и читаемости кода.


1
50
3

Ответы:

Решено

Вы можете использовать условие в функции ключа сортировки:

df.sort_values(
    ["string", "number"],
    key=lambda x: x.map(sort_string_like_this) if x.name == "string" else x,
)
   string    number
7    sort -1.673626
3    sort -0.212634
5    sort -0.071417
9    sort  0.413497
1    sort  0.489508
8  custom -1.787110
0  custom  0.230875
4  custom  0.535791
2  custom  0.671282
6  custom  2.119993

ИМХО, самый простой подход — использовать numpy.lexsort:

import numpy as np

out = df.iloc[np.lexsort([df['number'], df['string'].map(sort_string_like_this)])]

Другой вариант со словарем:

sorter = {'string': lambda x: x.map(sort_string_like_this),
          'number': lambda x: x
         }

out = df.sort_values(by=['string', 'number'], key=lambda x: sorter.get(x.name)(x))

Выход:

   string    number
5    sort -0.612289
1    sort -0.074041
9    sort  0.671288
7    sort  0.757922
3    sort  1.057676
4  custom -1.125380
0  custom -0.339373
2  custom -0.320231
8  custom -0.031580
6  custom  2.120829

Может быть, так? df.groupby(['string'])['number'].nsmallest()