Все ответы, представленные до сих пор, приводят к потенциально опасному поведению, поскольку вполне возможно, что вы выберете фиктивное значение, которое фактически является частью набора данных. Это становится все более вероятным, поскольку вы создаете группы со многими атрибутами. Проще говоря, этот подход не всегда хорошо обобщается.
Менее хакерское решение - использовать pd.drop_duplicates () для создания уникального индекса комбинаций значений, каждая из которых имеет свой собственный идентификатор, а затем группировать по этому идентификатору. Он более подробный, но выполняет свою работу:
def safe_groupby(df, group_cols, agg_dict):
group_id = 'group_id'
while group_id in df.columns:
group_id += 'x'
agg_col_order = (group_cols + list(agg_dict.keys()))
group_idx = df[group_cols].drop_duplicates()
group_idx[group_id] = np.arange(group_idx.shape[0])
df = df.merge(group_idx, on=group_cols)
df_agg = df.groupby(group_id, as_index=True)\
.agg(agg_dict)
df_agg = group_idx.set_index(group_id).join(df_agg)
df_agg.index.name = None
return df_agg[agg_col_order]
Обратите внимание, что теперь вы можете просто сделать следующее:
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')]))
Это вернет успешный результат, не беспокоясь о перезаписи реальных данных, которые были ошибочно приняты за фиктивное значение.