Сортировка pandas dataframe по группам и сохранение желаемого порядка - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть кадр данных, как показано ниже

df = pd.DataFrame({
    "Junk":list("aaaaaabbbcccc"),
    "Region":['West','West','West','West','East','East','East','South','South','South','North','North','North'],
    "Sales":[1, 3, 4, 2, 4, 2, 5, 7, 9, 7, 5, 9, 5]
})

+------+--------+-------+
| Junk | Region | Sales |
+------+--------+-------+
| a    | West   |     1 |
| a    | West   |     3 |
| a    | West   |     4 |
| a    | West   |     2 |
| a    | East   |     4 |
| a    | East   |     2 |
| b    | East   |     5 |
| b    | South  |     7 |
| b    | South  |     9 |
| c    | South  |     7 |
| c    | North  |     5 |
| c    | North  |     9 |
| c    | North  |     5 |
+------+--------+-------+

Я пытаюсь сделать две вещи

  1. Сортировать кадр данных по каждому региону

Я могу добиться этого с кодом ниже

df.sort_values(by = ['Region','Sales'])


+------+--------+-------+
| Junk | Region | Sales |
+------+--------+-------+
| a    | East   |     2 |
| a    | East   |     4 |
| b    | East   |     5 |
| c    | North  |     5 |
| c    | North  |     5 |
| c    | North  |     9 |
| b    | South  |     7 |
| c    | South  |     7 |
| b    | South  |     9 |
| a    | West   |     1 |
| a    | West   |     2 |
| a    | West   |     3 |
| a    | West   |     4 |
+------+--------+-------+

Но я хочу сохранить порядок столбца Region.Сначала следует указать West, затем East, затем South, а затем North

Требуемый выход

+--------+----------+---------+
|  Junk  |  Region  |  Sales  |
+--------+----------+---------+
|  a     | West     |       1 |
|  a     | West     |       2 |
|  a     | West     |       3 |
|  a     | West     |       4 |
|  a     | East     |       2 |
|  a     | East     |       4 |
|  b     | East     |       5 |
|  b     | South    |       7 |
|  c     | South    |       7 |
|  b     | South    |       9 |
|  c     | North    |       5 |
|  c     | North    |       5 |
|  c     | North    |       9 |
+--------+----------+---------+
Я просто хочу отсортировать Region = East и Region = North остальные регионы так, как они есть

Желаемый результат:

+--------+----------+---------+
|  Junk  |  Region  |  Sales  |
+--------+----------+---------+
|  a     | West     |       1 |
|  a     | West     |       3 |
|  a     | West     |       4 |
|  a     | West     |       2 |
|  a     | East     |       2 |
|  a     | East     |       4 |
|  b     | East     |       5 |
|  b     | South    |       7 |
|  b     | South    |       9 |
|  c     | South    |       7 |
|  c     | North    |       5 |
|  c     | North    |       5 |
|  c     | North    |       9 |
+--------+----------+---------+

Ответы [ 3 ]

0 голосов
/ 13 февраля 2019

Сначала создайте упорядоченный категориальный столбец , а затем сортируйте:

order = ['West', 'East', 'South', 'North']
df['Region'] = pd.CategoricalIndex(df['Region'], ordered=True, categories=order)

df = df.sort_values(by = ['Region','Sales'])
print (df)
   Junk Region  Sales
0     a   West      1
3     a   West      2
1     a   West      3
2     a   West      4
5     a   East      2
4     a   East      4
6     b   East      5
7     b  South      7
9     c  South      7
8     b  South      9
10    c  North      5
12    c  North      5
11    c  North      9

Решение с помощью map по словарю с созданием нового столбца, упорядочьте и затем удалите вспомогательный столбец:

order = {'West':1, 'East':2, 'South':3, 'North':4}

df = df.assign(tmp=df['Region'].map(order)).sort_values(by = ['tmp','Sales']).drop('tmp', 1)
print (df)
   Junk Region  Sales
6     a   West      1
0     a   West      2
7     a   West      3
8     a   West      4
2     a   East      2
1     a   East      4
3     b   East      5
4     b  South      7
9     c  South      7
5     b  South      9
10    c  North      5
12    c  North      5
11    c  North      9

Для секунды необходима сортировка по отфильтрованным строкам, но для предотвращения выравнивания данных назначьте массив пустых значений:

order = ['West', 'East', 'South', 'North']
df['Region'] = pd.CategoricalIndex(df['Region'], ordered=True, categories=order)

mask = df['Region'].isin(['North', 'East'])
df[mask] = df[mask].sort_values(['Region','Sales']).values
print (df)
   Junk Region  Sales
0     a   West      1
1     a   West      3
2     a   West      4
3     a   West      2
4     a   East      2
5     a   East      4
6     b   East      5
7     b  South      7
8     b  South      9
9     c  South      7
10    c  North      5
11    c  North      5
12    c  North      9

map альтернатива:

order = {'East':1, 'North':2}
df = df.assign(tmp=df['Region'].map(order))

mask = df['Region'].isin(['North', 'East'])
df[mask] = df[mask].sort_values(['tmp','Sales']).values
df = df.drop('tmp', axis=1)
0 голосов
/ 13 февраля 2019

Вы можете использовать groupby и воспользоваться параметром sort.Затем используйте apply и sort_values с условным условием:

sort_regions = ['North', 'East']
df.groupby('Region', sort=False).apply(
    lambda x: x.sort_values('Sales')
    if x['Region'].iloc[0] in sort_regions
    else x
).reset_index(drop=True)

Выход:

   Junk Region  Sales
0     a   West      1
1     a   West      3
2     a   West      4
3     a   West      2
4     a   East      2
5     a   East      4
6     b   East      5
7     b  South      7
8     b  South      9
9     c  South      7
10    c  North      5
11    c  North      5
12    c  North      9
0 голосов
/ 13 февраля 2019

Создайте сопоставление между west, east, south и north до 0, 1, 2, 3

>>> my_order = ['West','East','South','North']
>>> order = {key: i for i, key in enumerate(my_order)}
>>> order
{'West': 0, 'East': 1, 'South': 2, 'North': 3}

и используйте сопоставление для сортировки ключа:

>>> df.iloc[df['Region'].map(order).sort_values().index]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...