2016-05-06 2 views
0

Ich habe ein Datenframe, für das ich eine Reihe von Metriken nach bestimmten Spalten im Datenrahmen gruppieren müssen. Ich würde das gerne mit einer Schleife machen, aber ich kann mir nicht vorstellen, wie (wenn es einen richtigen Weg gibt).mit integrierten Pandas groupby Metriken aus einer Liste der genannten Metriken

Also, was ich versuche zu tun, im Grunde (semi-Pseudo-Code, dies nicht aus offensichtlichen Gründen nicht ausgeführt werden):

df = pd.DataFrame({'ID': ['A', 'B', 'A', 'C', 'B', 'C', 'A'], 
        'Score': range(7)}) 

group = df.groupby('ID') 
for stat in ['mean', 'min', 'max']: 
    group.stat() 

Das kann ich, wenn ich numpy und getattr verwenden, um die Arbeit. D.h .:

for stat in ['mean', 'min', 'max']: 
    df.groupby('ID').apply(getattr(np, stat)) 

Das Problem dabei ist, dass es die eingebaute in .mean() als die Verwendung von usw. Pandas bietet (zumindest für die Größe, den Datenrahmen arbeite ich mit) deutlich langsamer ist.

Gibt es einen geeigneteren Weg, dies zu erreichen?

+0

Sie sollten Ihre Daten nur einmal gruppieren. Nach der Gruppierung können Sie mehrere Aggregationen anwenden (Summe, Minimum, Maximum usw.). – Alexander

+0

Richtig, das war mein Fehler beim Erstellen des Spielzeug-Beispiels - ich habe die Gruppe außerhalb meiner Schleife in meinem tatsächlichen Anwendungsfall. Die Antwort von MaxU schlägt vor, agg zu verwenden, aber das führt zu einem etwas komplizierteren Ergebnis (wie ich im Kommentar unten seine Antwort anzeige): – user3014097

Antwort

0

UPDATE:

In [116]: stats = df.groupby('ID', as_index=False).agg(['mean','min','max']) 

In [117]: stats 
Out[117]: 
     Score 
     mean min max 
ID 
A 2.666667 0 6 
B 2.500000 1 4 
C 4.000000 3 5 

In [118]: stats.columns = ['{0[1]}_{0[0]}'.format(tup) for tup in stats.columns] 

In [119]: stats 
Out[119]: 
    mean_Score min_Score max_Score 
ID 
A  2.666667   0   6 
B  2.500000   1   4 
C  4.000000   3   5 

In [120]: stats.reset_index() 
Out[120]: 
    ID mean_Score min_Score max_Score 
0 A 2.666667   0   6 
1 B 2.500000   1   4 
2 C 4.000000   3   5 

alte Antwort:

In [51]: df.groupby('ID').agg(['mean','min','max']) 
Out[51]: 
     Score 
     mean min max 
ID 
A 2.666667 0 6 
B 2.500000 1 4 
C 4.000000 3 5 
+0

Ich bin mir über "agg" im Klaren, und ich könnte es auf diese Weise machen. Der eigentliche Anwendungsfall besteht jedoch darin, diese Metriken in einer Reihe von Spalten zu berechnen, diese Spalten umzubenennen und diese neuen Spalten mit der Bezeichnung für jede an den Spaltennamen angehängte Metrik wieder in den Datenrahmen einzufügen (der groupby befindet sich wirklich in einer Reihe) von den Zeitpunkten). Ich versuchte zu vermeiden, alle Spalten zu durchlaufen, die mit 'agg' zu tun, um schließlich das gewünschte Ergebnis – user3014097

+0

@ user3014097 generieren würde, möchten Sie diese Aggregationsfunktionen auf verschiedenen Spalten oder auf der gleichen anwenden? – MaxU

+0

Gleiche Spalten, aber mit 'agg' komme ich zu Teilmengen von Spalten. Also, wenn ich die Spalten A, B habe, endet ich mit 'df.A.mean',' df.A.min', etc - was ich nicht will. Ich brauche Spalten '[mean_A, min_A, etc] '. Um das zu erreichen, benutze ich 'agg', ich muss diese Spalten einzeln durchlaufen und generieren, soweit ich das beurteilen kann.Was gut funktioniert, wenn es nicht möglich ist, wie ich es im OP vorgeschlagen habe, ist es weniger prägnant. – user3014097

0

Hier ist eine benutzerdefinierte Gruppierung Funktion, die einen Datenrahmen nimmt, eine Liste der Spalten, auf denen Sie gruppieren möchten , eine Liste der Spalten, die Sie aggregieren möchten, und eine Liste der Funktionen, die auf diese Spalten angewendet werden sollen:

import re 
import numpy as np 
import pandas as pd 

# Sample data. 
np.random.seed(0) 
df = pd.DataFrame(np.random.randn(5, 3), columns=list('ABC')) 
df['labels'] = ['a'] * 3 + ['b'] * 2 
>>> df 
      A   B   C labels 
0 1.764052 0.400157 0.978738  a 
1 2.240893 1.867558 -0.977278  a 
2 0.950088 -0.151357 -0.103219  a 
3 0.410599 0.144044 1.454274  b 
4 0.761038 0.121675 0.443863  b 

# Custom function. 
def group_agg(df, groupby, columns=None, funcs=None): 
    if not funcs: 
     funcs = sum 
    if not columns: 
     columns = df.columns 
    gb = df.groupby(groupby) 
    dfs = [] 
    func_names = [re.findall(r'>?function (\w*)', str(foo))[0] for foo in funcs] 
    for col in columns: 
     col_names = (col + "_" + name for name in func_names) 
     names_func_dict = {col_name: foo for col_name, foo in zip(col_names, funcs)} 
     dfs.append(gb[col].agg(names_func_dict)) 
    return pd.concat(dfs, axis=1) 

# Example result. 
>>> group_agg(df, groupby=['labels'], funcs=[sum, np.mean], columns=['A', 'B']) 
      A_sum A_mean B_mean  B_sum 
labels           
a  4.955034 1.651678 0.705453 2.116358 
b  1.171636 0.585818 0.132859 0.265719 

Es gibt eine Regex-Anweisung, um die Funktionsnamen zu erhalten.

>>> [str(foo) for foo in funcs] 
['<built-in function sum>', '<function mean at 0x108f86ed8>'] 

>>> [re.findall(r'>?function (\w*)', str(foo))[0] for foo in funcs] 
['sum', 'mean'] 

Diese Namen werden dann mit der Spalte verknüpft, wobei ein Wörterbuchverständnis diese Namen der Funktion zuordnet.

Für Spalte A, zum Beispiel, das ist der Inhalt von names_func_dict:

{'A_mean': <function numpy.core.fromnumeric.mean>, 
'A_sum': <function sum>} 

Dieses Wörterbuch wird dann an die groupby[coll].agg() Funktion übergeben.