Tất cả các câu trả lời được cung cấp cho đến nay dẫn đến hành vi nguy hiểm tiềm tàng vì hoàn toàn có thể bạn chọn một giá trị giả thực sự là một phần của bộ dữ liệu. Điều này ngày càng có khả năng khi bạn tạo các nhóm có nhiều thuộc tính. Nói một cách đơn giản, cách tiếp cận không phải lúc nào cũng khái quát tốt.
Một giải pháp ít rắc rối hơn là sử dụng pd.drop_d repeatates () để tạo một chỉ mục duy nhất của các kết hợp giá trị với mỗi ID riêng của chúng, sau đó nhóm vào id đó. Nó dài dòng hơn nhưng hoàn thành công việc:
def safe_groupby(df, group_cols, agg_dict):
# set name of group col to unique value
group_id = 'group_id'
while group_id in df.columns:
group_id += 'x'
# get final order of columns
agg_col_order = (group_cols + list(agg_dict.keys()))
# create unique index of grouped values
group_idx = df[group_cols].drop_duplicates()
group_idx[group_id] = np.arange(group_idx.shape[0])
# merge unique index on dataframe
df = df.merge(group_idx, on=group_cols)
# group dataframe on group id and aggregate values
df_agg = df.groupby(group_id, as_index=True)\
.agg(agg_dict)
# merge grouped value index to results of aggregation
df_agg = group_idx.set_index(group_id).join(df_agg)
# rename index
df_agg.index.name = None
# return reordered columns
return df_agg[agg_col_order]
Lưu ý rằng bây giờ bạn có thể chỉ cần làm như sau:
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')]))
Điều này sẽ trả về kết quả thành công mà không phải lo lắng về việc ghi đè dữ liệu thực bị nhầm là giá trị giả.