Alle bisherigen Antworten führen möglicherweise zu gefährlichem Verhalten, da es durchaus möglich ist, dass Sie einen Dummy-Wert auswählen, der tatsächlich Teil des Datensatzes ist. Dies wird immer wahrscheinlicher, wenn Sie Gruppen mit vielen Attributen erstellen. Einfach ausgedrückt, der Ansatz verallgemeinert nicht immer gut.
Eine weniger hacky Lösung besteht darin, pd.drop_duplicates() zu verwenden, um einen eindeutigen Index von Wertekombinationen zu erstellen, von denen jeder eine eigene ID hat, und dann nach dieser ID zu gruppieren. Es ist ausführlicher, erledigt aber die Arbeit:
def safe_groupby(df, group_cols, agg_dict):
# Namen der Gruppenspalte auf eindeutigen Wert setzen
group_id = 'group_id'
while group_id in df.columns:
group_id += 'x'
# Endgültige Reihenfolge der Spalten erhalten
agg_col_order = (group_cols + list(agg_dict.keys()))
# Eindeutigen Index von gruppierten Werten erstellen
group_idx = df[group_cols].drop_duplicates()
group_idx[group_id] = np.arange(group_idx.shape[0])
# Eindeutigen Index mit dem DataFrame zusammenführen
df = df.merge(group_idx, on=group_cols)
# DataFrame nach Gruppen-ID gruppieren und Werte aggregieren
df_agg = df.groupby(group_id, as_index=True)\
.agg(agg_dict)
# Gruppierten Wertindex mit den Ergebnissen der Aggregation zusammenführen
df_agg = group_idx.set_index(group_id).join(df_agg)
# Index umbenennen
df_agg.index.name = None
# Neu sortierte Spalten zurückgeben
return df_agg[agg_col_order]
Beachten Sie, dass Sie jetzt einfach Folgendes tun können:
data_block = [np.tile([None, 'A'], 3),
np.repeat(['B', 'C'], 3),
[1] * (2 * 3)]
col_names = ['col_a', 'col_b', 'value']
test_df = pd.DataFrame(data_block, index=col_names).T
grouped_df = safe_groupby(test_df, ['col_a', 'col_b'],
OrderedDict([('value', 'sum')]))
Dies gibt das erfolgreiche Ergebnis zurück, ohne sich Sorgen machen zu müssen, dass echte Daten überschrieben werden, die fälschlicherweise als Dummy-Wert angesehen werden.