pandas 中的多个分组依据以帮助创建报告
Multiple group by in pandas with condition to help create report
我正在尝试从另一个报告创建一个合并报告。我拥有的初始数据采用这种格式
最终报告折叠了基础主管 ID 并跟踪了指示和分数的计数,如下所示:
我尝试的方法非常冗长乏味,如果要捕获的参数更多,则需要相当多的时间并显着增加代码行数。我正在寻找一种更智能的方法来创建此报告,涉及更少的代码行,并且可能会牺牲理解方法等可读性。非常感谢任何帮助。
我的代码如下:
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)
我认为与其在不同的操作中分组并合并回原始 df,不如一次性完成,然后添加 'rate'。类似于:
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
我正在尝试从另一个报告创建一个合并报告。我拥有的初始数据采用这种格式
最终报告折叠了基础主管 ID 并跟踪了指示和分数的计数,如下所示:
我尝试的方法非常冗长乏味,如果要捕获的参数更多,则需要相当多的时间并显着增加代码行数。我正在寻找一种更智能的方法来创建此报告,涉及更少的代码行,并且可能会牺牲理解方法等可读性。非常感谢任何帮助。
我的代码如下:
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)
我认为与其在不同的操作中分组并合并回原始 df,不如一次性完成,然后添加 'rate'。类似于:
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