Несколько групп в пандах с условием, помогающим создать отчет

Я пытаюсь создать сводный отчет из другого отчета. Исходные данные у меня есть в этом формате Несколько групп в пандах с условием, помогающим создать отчет

Окончательный отчет сворачивает базовый идентификатор супервайзера и отслеживает количество направлений и оценок, что выглядит следующим образом: Несколько групп в пандах с условием, помогающим создать отчет

То, что я пробовал, довольно длинное и утомительное, и если нужно захватить гораздо больше параметров, это требует довольно много времени и значительно увеличивает количество строк кода. Я ищу более разумный способ создания этого отчета, включающий меньше строк кода и могу пожертвовать удобочитаемостью, например методами понимания. Любая помощь приветствуется.

Мой код ниже:

xdf = pd.DataFrame({'ID':[101,102,103,104,202,203,204,303,306,309,401,403,407,408,507,508,509],
                    'SID':[100,100,100,100,200,200,200,300,300,300,400,400,400,400,500,500,500],
                    'Active':['Y','N','Y','Y','Y','Y','Y','Y','N','N','N','Y','Y','Y','N','N','Y'],
                    'Score':[4,0,3,4,4,4,5,3,2,2,3,4,4,5,1,1,5,]})

xdf['Active'] = np.where(xdf['Active']=='Y',1,0)

print(xdf)

xdf_tc = xdf.groupby('SID')['ID'].count().reset_index()
xdf_ac = xdf.groupby('SID')['Active'].sum().reset_index()
xdf_sc = xdf.groupby('SID')['Score'].mean().reset_index()

ydf = pd.merge(xdf_tc,xdf_ac,how='left',on='SID')
ydf = pd.merge(ydf,xdf_sc,how='left',on='SID')
ydf = ydf.rename(columns = {'ID': 'total',
                    'Score':'agg_score'})

ydf['rate'] = round(1-(ydf['Active']/ydf['total']),2)
print(ydf)
0
0
29
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Я думаю, что вместо того, чтобы группировать по разным операциям и возвращаться к исходному df, вы могли бы сделать это за один раз, а затем добавить «скорость». Что-то вроде:

tmp=xdf.groupby('SID').agg({'ID':'count','Active':'sum','Score':'mean'}).rename(columns = {'ID': 'total','Score':'agg_score'})
tmp['rate'] = round(1-(tmp['Active']/tmp['total']),2)
tmp

Вы можете упростить свое решение с помощью именованной агрегации:

xdf['Active'] = np.where(xdf['Active']=='Y',1,0)

ydf = xdf.groupby('SID').agg(total=('ID','count'),
                             Active=('Active','sum'),
                             agg_score=('Score','mean'))
ydf['rate'] = round(1-(ydf['Active']/ydf['total']),2)           
print(ydf)
     total  Active  agg_score  rate
SID                                
100      4       3   2.750000  0.25
200      3       3   4.333333  0.00
300      3       1   2.333333  0.67
400      4       3   4.000000  0.25
500      3       1   2.333333  0.67

Также возможно использование:

ydf = (xdf.assign(Active = xdf['Active']=='Y')
          .groupby('SID')
          .agg(total=('ID','count'),
               Active=('Active','sum'),
               agg_score=('Score','mean')))
ydf['rate'] = round(1-(ydf['Active']/ydf['total']),2)           
print(ydf)
     total  Active  agg_score  rate
SID                                
100      4       3   2.750000  0.25
200      3       3   4.333333  0.00
300      3       1   2.333333  0.67
400      4       3   4.000000  0.25
500      3       1   2.333333  0.67

Вы можете использовать named aggregation, а если важен порядок столбцов, используйте reindex в конце.

res = df.groupby('SID').agg(total=('SID','count'), Active=('Active', lambda x: (x=='Y').sum()), agg_score=('Score', 'mean'))
res['rate'] = [f"{1-x:.0%}" for x in res['Active']/res['total']]
res.reindex(columns=['total', 'Active','rate','agg_score'])

print(res)

     total  Active rate  agg_score
SID                               
100      4       3  25%   2.750000
200      3       3   0%   4.333333
300      3       1  67%   2.333333
400      4       3  25%   4.000000
500      3       1  67%   2.333333


Другие вопросы по теме