Ordinare all'interno del gruppo senza modificare l'ordine del gruppo?
Non riesco a trovare una risposta aggiornata su questo online. Il problema che ho è essenzialmente lo stesso di questa domanda , cioè voglio ordinare per dire revenue
all'interno group
senza cambiare l'ordine di group
nel mio set di dati.
La risposta a quel thread è sbagliata, funziona solo perché c'erano solo due gruppi nell'esempio che erano in ordine anti-alfabetico.
Quando provo df.groupby('group').sort_values('revenue')
, ottengo un errore 'DataFrameGroupBy' object has no attribute 'sort_values'
.
Come posso fare questo?
DataFrame di esempio:
name group revenue
0 Name1 GroupB 1
3 Name4 GroupA 4
4 Name5 GroupA 5
8 Name7 GroupC 9
1 Name2 GroupB 2
2 Name3 GroupB 3
5 Name6 GroupA 6
6 Name7 GroupC 7
7 Name7 GroupC 8
Uscita prevista:
name group revenue
2 Name3 GroupB 3
1 Name2 GroupB 2
0 Name1 GroupB 1
5 Name6 GroupA 6
4 Name5 GroupA 5
3 Name4 GroupA 4
8 Name7 GroupC 9
7 Name7 GroupC 8
6 Name7 GroupC 7
Risposte
È possibile creare una nuova colonna temporanea che trasforma B
, A
e C
in 1
, 2
e 3
, in modo da mantenere l'ordine del non ordinato. Quindi, rilascia la colonna temporanea. Nella risposta # 1, questo è più dinamico e funzionerà se i group
valori delle colonne non vengono raggruppati consecutivamente. Per la risposta # 2, devono essere consecutivi (gli input per la risposta # 1 e la risposta # 2 sono ordinati in modo diverso)
Risposta # 1 aggiornata (per commento - i gruppi non sono consecutivi in righe, ma vogliamo comunque ordinarli correttamente in base all'ordine di apparizione del primo valore all'interno di ogni gruppo.) Il codice [l for l in enumerate((df['group'].unique()))]
assegnerà un numero a ciascun gruppo a seconda del ordine del primo valore della group
colonna nel dataframe.
In[1]:
name group revenue
0 Name1 GroupB 1
3 Name4 GroupA 4
4 Name5 GroupA 5
8 Name7 GroupC 9
1 Name2 GroupB 2
2 Name3 GroupB 3
5 Name6 GroupA 6
6 Name7 GroupC 7
7 Name7 GroupC 8
dft = pd.DataFrame([l for l in enumerate((df['group'].unique()))], columns=['group_number','group'])
df = pd.merge(df, dft, how='left', on='group').sort_values(['group_number', 'revenue'], ascending = [True, False])
df
Out[1]:
name group revenue group_number
5 Name3 GroupB 3 0
4 Name2 GroupB 2 0
0 Name1 GroupB 1 0
6 Name6 GroupA 6 1
2 Name5 GroupA 5 1
1 Name4 GroupA 4 1
3 Name7 GroupC 9 2
8 Name7 GroupC 8 2
7 Name7 GroupC 7 2
Volevo evidenziare l'output della riga di codice prima dell'unione e dft
dell'ordinamento enumerate
.
dft = pd.DataFrame([l for l in enumerate((df['group'].unique()))], columns=['group_number','group'])
dft
Out[2]:
group_number group
0 0 GroupB
1 1 GroupA
2 2 GroupC
Risposta # 2
import pandas as pd
df = pd.DataFrame({'name': ['Name1','Name2','Name3','Name4','Name5','Name6', 'Name7', 'Name7', 'Name7'],
'group':['GroupB','GroupB','GroupB','GroupA','GroupA','GroupA','GroupC','GroupC','GroupC'],'revenue':[1,2,3,4,5,6,7,8,9]})
df['cs'] = (df['group'] != df['group'].shift(1)).cumsum()
df = df.sort_values(['cs', 'revenue'], ascending = [True, False])
df
Out[11]:
name group revenue cs
2 Name3 GroupB 3 1
1 Name2 GroupB 2 1
0 Name1 GroupB 1 1
5 Name6 GroupA 6 2
4 Name5 GroupA 5 2
3 Name4 GroupA 4 2
8 Name7 GroupC 9 3
7 Name7 GroupC 8 3
6 Name7 GroupC 7 3
Per entrambe le risposte, rilascia la colonna:
df = df.drop('cs', axis=1)
Out[12]:
name group revenue
2 Name3 GroupB 3
1 Name2 GroupB 2
0 Name1 GroupB 1
5 Name6 GroupA 6
4 Name5 GroupA 5
3 Name4 GroupA 4
8 Name7 GroupC 9
7 Name7 GroupC 8
6 Name7 GroupC 7
Perché usare groupby? Potresti semplicemente concatenare più chiamate sort_values per ottenere l'ordinamento corretto. ad esempio, utilizzando dati simili alla domanda collegata e volevi ordinare in base alle entrate decrescenti ma mantenere i gruppi in aumento, potresti fare:
import pandas as pd
df = pd.DataFrame({'name': ['Name1','Name2','Name3','Name4','Name5','Name6', 'Name7', 'Name7', 'Name7'],
'group':['GroupB','GroupB','GroupB','GroupA','GroupA','GroupA','GroupC','GroupC','GroupC'],'revenue':[1,2,3,4,5,6,7,8,9]})
df.sort_values(by='revenue', ascending= False).sort_values(by='group')
Che tornerebbe:
name group revenue
5 Name6 GroupA 6
4 Name5 GroupA 5
3 Name4 GroupA 4
2 Name3 GroupB 3
1 Name2 GroupB 2
0 Name1 GroupB 1
8 Name7 GroupC 9
7 Name7 GroupC 8
6 Name7 GroupC 7