2017-03-01 7 views
2

ich einen Datenrahmen haben, die etwa wie folgt aussieht:Pandas groupby Aggregat neue Spalten

A B C D 
1 10 22 14 
1 12 20 37 
1 11 8 18 
1 10 10 6 
2 11 13 4 
2 12 10 12 
3 14 0 5 

und eine Funktion, die etwa wie folgt aussieht (Hinweis: es ist tatsächlich etwas komplizierter zu tun, die nicht so leicht sein kann getrennt in drei unabhängige Anrufe, aber ich bin eine Vereinfachung für Klarheit):

def myfunc(g): 
    return min(g), mean(g), max(g) 

ich möchte groupby auf A mit myfunc verwenden, um eine Ausgabe zu erhalten auf Spalten 01.231.und C (ohne Berücksichtigung D) so etwas wie dieses:

   B    C 
    min mean max min mean max 
A 
1 10 10.75 12  8 15.0 22 
2 11 11.50 12 10 11.5 13 
3 14 14.00 14  0 0.0 0 

Ich kann folgendes tun:

df2.groupby('A')[['B','C']].agg(
    { 
     'min': lambda g: myfunc(g)[0], 
     'mean': lambda g: myfunc(g)[1], 
     'max': lambda g: myfunc(g)[2] 
    }) 

Aber damals abgesehen davon ist hässlich und ruft myfunc mehrfach-I mit

am Ende

Ich kann .swaplevel(axis=1) verwenden, um die Spaltenstufen zu tauschen, aber selbst dann B und C sind in mehreren doppelten Spalten, und mit den mehreren Funktionsaufrufen fühlt es sich an, als würde man den falschen Baum anbellen.

Antwort

4

Wenn Sie myfunc vereinbaren Sie einen Datenrahmen, deren Spalten zurückzugeben sind ['A','B','C','D'] und deren Zeilen Index sind ['min', 'mean', 'max'], dann könnten Sie groupby/apply verwenden, um die Funktion aufzurufen (einmal für jede Gruppe) und die Ergebnisse verketten, wie gewünscht:

import numpy as np 
import pandas as pd 

def myfunc(g): 
    result = pd.DataFrame({'min':np.min(g), 
          'mean':np.mean(g), 
          'max':np.max(g)}).T 
    return result 

df = pd.DataFrame({'A': [1, 1, 1, 1, 2, 2, 3], 
'B': [10, 12, 11, 10, 11, 12, 14], 
'C': [22, 20, 8, 10, 13, 10, 0], 
'D': [14, 37, 18, 6, 4, 12, 5]}) 

result = df.groupby('A')[['B','C']].apply(myfunc) 
result = result.unstack(level=-1) 
print(result) 

druckt

 B     C    
    max mean min max mean min 
A          
1 12.0 10.75 10.0 22.0 15.0 8.0 
2 12.0 11.50 11.0 13.0 11.5 10.0 
3 14.0 14.00 14.0 0.0 0.0 0.0 

Für andere, die über diese laufen kann und die es nicht tun benötigen Sie eine benutzerdefinierte Funktion, beachten Sie , dass es Ihnen obliegt, immer builtin aggregators (unten, durch die Strings 'min', 'mean' und 'max' angegeben) wenn möglich zu verwenden. Sie bieten eine bessere Leistung als benutzerdefinierte Python-Funktionen. Glücklicherweise erzeugt dieses Spielzeugproblem das gewünschte Ergebnis:

In [99]: df.groupby('A')[['B','C']].agg(['min','mean','max']) 
Out[99]: 
    B    C   
    min mean max min mean max 
A        
1 10 10.75 12 8 15.0 22 
2 11 11.50 12 10 11.5 13 
3 14 14.00 14 0 0.0 0 
-1

So etwas könnte funktionieren.

df2.groupby('A')[['B','C']] 
aggregated = df2.agg(['min', 'mean', 'max']) 

dann könnte man Swap-Ebene verwendet die Spaltenreihenfolge um

aggregated.columns = aggregated.columns.swaplevel(0, 1) 
aggregated.sortlevel(0, axis=1, inplace=True) 
+0

HINWEIS getauscht zu bekommen: es ist tatsächlich etwas komplizierter zu tun, die nicht ohne weiteres in drei unabhängige Anrufe getrennt werden, aber ich bin Vereinfachung für Klarheit – Dan