Группировка Python по рангу в двух разных направлениях

У меня есть фрейм данных, d:

    Position    Operation   Side    Price   Size
9   9   0   1   0.7289  -16
8   8   0   1   0.729   -427
7   7   0   1   0.7291  -267
6   6   0   1   0.7292  -15
5   5   0   1   0.7293  -16
4   4   0   1   0.7294  -16
3   3   0   1   0.7295  -426
2   2   0   1   0.7296  -8
1   1   0   1   0.7297  -14
0   0   0   1   0.7298  -37
10  0   0   0   0.7299  6
11  1   0   0   0.73    34
12  2   0   0   0.7301  7
13  3   0   0   0.7302  9
14  4   0   0   0.7303  16
15  5   0   0   0.7304  15
16  6   0   0   0.7305  429
17  7   0   0   0.7306  16
18  8   0   0   0.7307  265
19  9   0   0   0.7308  18

Используйте приведенные ниже обновления для d для перерасчета Position:

d['Position'] = d.groupby('Side')['Price'].rank().astype('int').sub(1)

Но поскольку порядок сортировки различен для каждой Side группы, есть ли способ отсортировать ascending для одной группы и descending для другой?

🤔 А знаете ли вы, что...
Синтаксис Python известен своей простотой и читаемостью.


70
2

Ответы:

Вы можете использовать groupby.apply для доступа к group.name:

d['rank'] = (d.groupby('Side')['Price']
              .apply(lambda x: x.rank(ascending=x.name==0).astype('int').sub(1))
              .droplevel(0)
             )

Выход:

    Position  Operation  Side   Price  Size  rank
9          9          0     1  0.7289   -16     9
8          8          0     1  0.7290  -427     8
7          7          0     1  0.7291  -267     7
6          6          0     1  0.7292   -15     6
5          5          0     1  0.7293   -16     5
4          4          0     1  0.7294   -16     4
3          3          0     1  0.7295  -426     3
2          2          0     1  0.7296    -8     2
1          1          0     1  0.7297   -14     1
0          0          0     1  0.7298   -37     0
10         0          0     0  0.7299     6     0
11         1          0     0  0.7300    34     1
12         2          0     0  0.7301     7     2
13         3          0     0  0.7302     9     3
14         4          0     0  0.7303    16     4
15         5          0     0  0.7304    15     5
16         6          0     0  0.7305   429     6
17         7          0     0  0.7306    16     7
18         8          0     0  0.7307   265     8
19         9          0     0  0.7308    18     9

Решено

Код

Я думаю, что простым решением является ранжирование групп путем умножения их цены на -1, при этом порядок ранжирования должен быть обратным.

cond = d['Side'].eq(1) # you can use isin when apply to multiple group
d['rank'] = (
    d['Price']
    .mask(cond, d['Price'].mul(-1))
    .groupby(d['Side']).rank().astype('int').sub(1)
)