Skip to content

Mehrere Funktionen auf mehrere Groupby-Spalten anwenden

Wir prüfen jede Bewertung auf unserer Website gründlich, mit dem Ziel, Ihnen immer die genauesten und aktuellsten Informationen zu zeigen.

Lösung:

Die zweite Hälfte der derzeit akzeptierten Antwort ist veraltet und hat zwei Verwerfungen. Erstens und am wichtigsten ist, dass Sie nicht mehr ein Wörterbuch von Wörterbüchern an die Funktion agg groupby-Methode übergeben. Zweitens, verwenden Sie niemals .ix.

Wenn Sie mit zwei getrennten Spalten gleichzeitig arbeiten möchten, empfehle ich die Verwendung der Methode apply Methode, die implizit einen DataFrame an die angewandte Funktion übergibt. Verwenden wir einen ähnlichen DataFrame wie den von oben

df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]
df

          a         b         c         d  group
0  0.418500  0.030955  0.874869  0.145641      0
1  0.446069  0.901153  0.095052  0.487040      0
2  0.843026  0.936169  0.926090  0.041722      1
3  0.635846  0.439175  0.828787  0.714123      1

Ein Wörterbuch, das von Spaltennamen auf Aggregationsfunktionen abgebildet wird, ist immer noch ein guter Weg, um eine Aggregation durchzuführen.

df.groupby('group').agg({'a':['sum', 'max'], 
                         'b':'mean', 
                         'c':'sum', 
                         'd': lambda x: x.max() - x.min()})

              a                   b         c         d
            sum       max      mean       sum  
group                                                  
0      0.864569  0.446069  0.466054  0.969921  0.341399
1      1.478872  0.843026  0.687672  1.754877  0.672401

Wenn Sie den hässlichen Lambda-Spaltennamen nicht mögen, können Sie eine normale Funktion verwenden und der speziellen Funktion einen eigenen Namen geben __name__ Attribut einen benutzerdefinierten Namen geben, etwa so:

def max_min(x):
    return x.max() - x.min()

max_min.__name__ = 'Max minus Min'

df.groupby('group').agg({'a':['sum', 'max'], 
                         'b':'mean', 
                         'c':'sum', 
                         'd': max_min})

              a                   b         c             d
            sum       max      mean       sum Max minus Min
group                                                      
0      0.864569  0.446069  0.466054  0.969921      0.341399
1      1.478872  0.843026  0.687672  1.754877      0.672401

Verwendung von apply und der Rückgabe einer Serie

Wenn Sie nun mehrere Spalten haben, die miteinander interagieren müssen, können Sie nicht aggverwenden, das implizit eine Reihe an die Aggregationsfunktion übergibt. Bei Verwendung von apply wird die gesamte Gruppe als DataFrame an die Funktion übergeben.

Ich empfehle, eine einzige benutzerdefinierte Funktion zu erstellen, die eine Serie aller Aggregationen zurückgibt. Verwenden Sie den Index der Serie als Beschriftung für die neuen Spalten:

def f(x):
    d = {}
    d['a_sum'] = x['a'].sum()
    d['a_max'] = x['a'].max()
    d['b_mean'] = x['b'].mean()
    d['c_d_prodsum'] = (x['c'] * x['d']).sum()
    return pd.Series(d, index=['a_sum', 'a_max', 'b_mean', 'c_d_prodsum'])

df.groupby('group').apply(f)

         a_sum     a_max    b_mean  c_d_prodsum
group                                           
0      0.864569  0.446069  0.466054     0.173711
1      1.478872  0.843026  0.687672     0.630494

Wenn Sie MultiIndexe lieben, können Sie immer noch eine Serie mit einem wie diesem zurückgeben:

    def f_mi(x):
        d = []
        d.append(x['a'].sum())
        d.append(x['a'].max())
        d.append(x['b'].mean())
        d.append((x['c'] * x['d']).sum())
        return pd.Series(d, index=[['a', 'a', 'b', 'c_d'], 
                                   ['sum', 'max', 'mean', 'prodsum']])

df.groupby('group').apply(f_mi)

              a                   b       c_d
            sum       max      mean   prodsum
group                                        
0      0.864569  0.446069  0.466054  0.173711
1      1.478872  0.843026  0.687672  0.630494

Für den ersten Teil können Sie ein Diktat von Spaltennamen als Schlüssel und eine Liste von Funktionen für die Werte übergeben:

In [28]: df
Out[28]:
          A         B         C         D         E  GRP
0  0.395670  0.219560  0.600644  0.613445  0.242893    0
1  0.323911  0.464584  0.107215  0.204072  0.927325    0
2  0.321358  0.076037  0.166946  0.439661  0.914612    1
3  0.133466  0.447946  0.014815  0.130781  0.268290    1

In [26]: f = {'A':['sum','mean'], 'B':['prod']}

In [27]: df.groupby('GRP').agg(f)
Out[27]:
            A                   B
          sum      mean      prod
GRP
0    0.719580  0.359790  0.102004
1    0.454824  0.227412  0.034060

UPDATE 1:

Da die Aggregatfunktion mit Serien arbeitet, gehen Verweise auf die anderen Spaltennamen verloren. Um dies zu umgehen, können Sie auf den vollständigen Datenrahmen verweisen und ihn mithilfe der Gruppenindizes innerhalb der Lambda-Funktion indizieren.

Hier ein kleiner Trick, um das Problem zu umgehen:

In [67]: f = {'A':['sum','mean'], 'B':['prod'], 'D': lambda g: df.loc[g.index].E.sum()}

In [69]: df.groupby('GRP').agg(f)
Out[69]:
            A                   B         D
          sum      mean      prod  
GRP
0    0.719580  0.359790  0.102004  1.170219
1    0.454824  0.227412  0.034060  1.182901

Hier besteht die resultierende Spalte "D" aus den summierten "E"-Werten.

UPDATE 2:

Hier ist eine Methode, die meiner Meinung nach alles tut, was Sie verlangen. Erstellen Sie zunächst eine benutzerdefinierte Lambda-Funktion. Im Folgenden verweist g auf die Gruppe. Beim Aggregieren wird g eine Serie sein. Übergabe g.index an df.ix[] wird die aktuelle Gruppe aus df ausgewählt. Dann prüfe ich, ob Spalte C kleiner als 0,5 ist. Die zurückgegebene boolesche Reihe wird an g[] übergeben, der nur die Zeilen auswählt, die die Kriterien erfüllen.

In [95]: cust = lambda g: g[df.loc[g.index]['C'] < 0.5].sum()

In [96]: f = {'A':['sum','mean'], 'B':['prod'], 'D': {'my name': cust}}

In [97]: df.groupby('GRP').agg(f)
Out[97]:
            A                   B         D
          sum      mean      prod   my name
GRP
0    0.719580  0.359790  0.102004  0.204072
1    0.454824  0.227412  0.034060  0.570441

Pandas >= 0.25.0, benannte Aggregationen

Seit der Pandas-Version 0.25.0 oder höher bewegen wir uns weg von der wörterbuchbasierten Aggregation und Umbenennung und bewegen uns hin zu benannten Aggregationen, die eine tuple. Jetzt können wir gleichzeitig aggregieren und umbenennen, um einen informativeren Spaltennamen zu erhalten:

Beispiel:

df = pd.DataFrame(np.random.rand(4,4), columns=list('abcd'))
df['group'] = [0, 0, 1, 1]

          a         b         c         d  group
0  0.521279  0.914988  0.054057  0.125668      0
1  0.426058  0.828890  0.784093  0.446211      0
2  0.363136  0.843751  0.184967  0.467351      1
3  0.241012  0.470053  0.358018  0.525032      1

anwenden. GroupBy.agg mit benannter Aggregation:

df.groupby('group').agg(
             a_sum=('a', 'sum'),
             a_mean=('a', 'mean'),
             b_mean=('b', 'mean'),
             c_sum=('c', 'sum'),
             d_range=('d', lambda x: x.max() - x.min())
)

          a_sum    a_mean    b_mean     c_sum   d_range
group                                                  
0      0.947337  0.473668  0.871939  0.838150  0.320543
1      0.604149  0.302074  0.656902  0.542985  0.057681

Bewertungen und Kommentare

Wenn Sie ein Hindernis und die Fähigkeit haben, unser Schreiben zu verbessern, empfehlen wir Ihnen, eine Interpretation zu hinterlassen, und wir werden uns diese mit Interesse ansehen.



Nutzen Sie unsere Suchmaschine

Suche
Generic filters

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.