Я начну с первых 1 столбцов, и оттуда вы сможете сами разобраться, как сделать столбцы Top2:
#First two columns only need to be grouped by customer number
grouped_df = data.groupby("Cus_No")
out_df = grouped_df.Amount.agg({"Tot_Amount": sum})
out_df["Tot_Freq"] = grouped_df.Amount.count().values
# Assuming Purchase_date is pd.datetime type, need this later
data["month_year"] = data.Purchase_date.apply(lambda d: (d.month, d.year))
# Next we group by cus_no and then branch_code
branch_group = data.groupby(["Cus_No", "Branch_code"])
top_sums = branch_group.Amount.sum().groupby(level=0, group_keys=False).nlargest(1)
out_df["Top_1_Branch"] = top_sums.index.get_level_values(1).values
out_df["Top1_Tot_Sum"] = top_sums.values
#Now we have retrieve information from the branch_group DF based on indexes from
#the top1 information we have in the out_df DF. The only way I can think of doing
#this is iterative indexing
out_df["Top1_Tot_Freq"] = [branch_group.loc[(cus_no, top_branch)].shape[0]
for _, (cus_no, top_branch) in
out_df.loc[: ["Cus_No", "Top_1_Branch"]].iterrows()]
months_per_top1 = np.array([branch_group.loc[(cus_no, top_branch), "month_year"].nunique()
for _, (cus_no, top_branch) in
out_df.loc[: ["Cus_No", "Top_1_Branch"]].iterrows()])
out_df["Top1_avg_mon_sum"] = out_df.Top1_Tot_Sum/months_per_top1
out_df["Top1_avg_mon_freq"] = out_df.Top1_Tot_Freq/months_per_top1
Может быть, не самый эффективныйкод со списком понимания, но это должно примерно сделать работу.Будьте осторожны с порядком, для которого вы устанавливаете значения в out_df.Возможно, вы захотите «присоединиться» к номеру клиента, чтобы убедиться, что в правильных строках в out_df указаны правильные значения.
Редактировать: Начальные подсказки для верхней 2 ветви:
grouped = branch_group.Amount.sum().groupby(level=0, group_keys=False)
second_sums = grouped.transform(lambda x: x.nlargest(2).min())
out_df["Top_2_Branch"] = second_sums.index.get_level_values(1).values
Остальное практически идентично.