У меня есть следующий сгруппированный фрейм данных:

                 Value1      Value2

    Category   
------------------------------------   
0          0         62          44 
           1         55          46 
           2         73          75 
1          0         61          49 
           1         55          46 
           2         34          35  
2          0         62          48 
           1         55          46 
           2         44          25 

Я хочу для каждой группы изменить порядок столбца «Значение1» по возрастанию, сохраняя порядок столбца «Категория». Цель состоит в том, чтобы «Категория» 0 соответствовала самому низкому значению «Value1», а «Category» 5 соответствовала наивысшему значению «Value1». Значения «Value2» будут соответствовать исходному значению «Value1», которому они соответствовали. Это выходной кадр данных, который я хочу создать:

                 Value1      Value2

    Category   
------------------------------------   
0          0         55          46    
           1         62          44
           2         73          75                 
1          0         34          35
           1         55          46  
           2         61          49
2          0         44          25
           1         55          46 
           2         62          48

Как я могу сделать это на Python? Я пробовал использовать .reset_index() и `.sort_values ​​(), но я просто не получаю желаемый сгруппированный фрейм данных. Я пытался:

df.sort_values(['Value1'],ascending=True).groupby('Category')

Но это просто производит: <pandas.core.groupby.generic.DataFrameGroupBy object at ...>, что бесполезно.

0
LostinSpatialAnalysis 24 Ноя 2021 в 10:32

4 ответа

Лучший ответ

Один из способов использования sort_values с именем индекса:

tmp = df.index.names
df.index.names = ["tmp", "Category"]
new_df = df.sort_values(["tmp", "Value1"])
new_df.index = df.index.rename(tmp)
print(new_df)

Выход:

            Value1  Value2
  Category                
0 0             55      46
  1             62      44
  2             73      75
1 0             34      35
  1             55      46
  2             61      49
2 0             44      25
  1             55      46
  2             62      48
2
Chris 24 Ноя 2021 в 10:47

Вы можете применить его следующим образом:

import pandas as pd

df = pd.DataFrame({'col1': [0, 1, 2, 0, 1, 2], 'col2': [8, 9, 6, 40, 3, 20], 'col3': [5, 6, 0, 40, 3, 20]})
sorted_df = df.sort_values(['col2'], ascending=True)
df[['col2', 'col3']] = sorted_df[['col2', 'col3']].values
print(df)

Выход:

   col1  col2  col3
0     0     3     3
1     1     6     0
2     2     8     5
3     0     9     6
4     1    20    20
5     2    40    40
1
mozway 24 Ноя 2021 в 11:13
1
Я взял на себя смелость упростить назначение столбцов;) (и +1 за ваш ответ)
 – 
mozway
24 Ноя 2021 в 11:13

Вы можете отсортировать фрейм данных по значениям и первому уровню индекса:

>>> df = (df.sort_values(by=['Value1', 'Value2'])
            .sort_index(level=0, sort_remaining=False)
          )

            Value1  Value2
  Category                
0 1             55      46
  0             62      44
  2             73      75
1 2             34      35
  1             55      46
  0             61      49
2 2             44      25
  1             55      46
  0             62      48

Затем вам нужно переписать level1, используя cumcount для каждой группы:

df.sort_values(by=['Value1', 'Value2']).sort_index(level=0, sort_remaining=False)
idx = pd.MultiIndex.from_arrays([df.index.get_level_values(0),
                                 pd.Series(range(len(df))).groupby(df.index.get_level_values(0)).cumcount()],
                                names=(None, 'Category')
                                )
df.index = idx

Выход:

            Value1  Value2
  Category                
0 0             55      46
  1             62      44
  2             73      75
1 0             34      35
  1             55      46
  2             61      49
2 0             44      25
  1             55      46
  2             62      48
0
mozway 24 Ноя 2021 в 10:56

Однострочное решение должно быть DataFrame.rename_axis с помощью DataFrame.sort_values и DataFrame.set_index:

df = df.rename_axis(index={None:'tmp'}).sort_values(['tmp', "Value1"]).set_index(df.index)
print (df)
            Value1  Value2
  Category                
0 0             55      46
  1             62      44
  2             73      75
1 0             34      35
  1             55      46
  2             61      49
2 0             44      25
  1             55      46
  2             62      48
0
jezrael 24 Ноя 2021 в 11:34
1
Я не сбрасываю level1 по запросу;)
 – 
mozway
24 Ноя 2021 в 11:32
1
- заменить последний rename_axis на set_index решить эту проблему
 – 
jezrael
24 Ноя 2021 в 11:38