Pandas Groupby:同一列上的聚合,但总计基于两个不同的标准/数据框
Posted
技术标签:
【中文标题】Pandas Groupby:同一列上的聚合,但总计基于两个不同的标准/数据框【英文标题】:Pandas Groupby: Aggregations on the same column but totals based on two different critera / dataframes 【发布时间】:2018-12-16 21:34:59 【问题描述】:我的数据框:
display_name security_type1 currency_str state
A GOVT USD Done
B CORP NZD Passed
B CORP USD Done
C CORP EUR Done
C CORP EUR Traded Away
C CORP GBP Done
C CORP GBP Done
C CORP USD Done
我想要的结果是:
一个。分组display_name
、security_type1
和currency_str
b.然后计算column state
包含Done
的行数并更新列Done_RFQ
c。显示每个display_name
、security_type1
和currency_str
组合的总行数并更新列Total_RFQ
d。最后显示完成占总数的百分比,即Done_Pct = Done_RFQ / Total_RFQ
display_name security_type1 currency_str Done_RFQ Total_RFQ Done_Pct
A GOVT USD 1 1 100%
B CORP USD 1 2 50%
C CORP EUR 1 5 20%
C CORP GBP 2 5 40%
C CORP USD 1 5 20%
我的代码除了Total_RFQ
和Done_Pct
之外都可以工作
d = [('Done_RFQ', 'size')]
df_Done_Client = df[
df['state'].str.contains('Done')
][['display_name','security_type1','currency_str','state']].copy()
df_Done_Client =
df_Done_Client.groupby(['display_name','security_type1','currency_str'])['state'].agg(d).reset_index()
# Sum of all Done RFQ's per display_name
Sum_of_Done_For_Month = df_Done_Client.groupby('display_name')['Done_RFQ'].transform('sum')
df_Done_Client['Total_Done_RFQ'] = Sum_of_Done_For_Month
df_Done_Client['Done_Pct'] = df_Done_Client['Done_RFQ_For_Month'].div(Sum_of_Done_For_Month).round(5)
display(df_Done_Client)
我不清楚如何计算这个总数,因为它需要来自另一个数据框,即相同的字段但没有“完成”标准。
df_All_Client = df[['display_name','security_type1','currency_str','state']].copy()
【问题讨论】:
【参考方案1】:我认为需要Total_RFQ
列和size
- 总计数和Done_RFQ
按布尔掩码计数 - 与True
s 的Done
和sum
比较:
d = [('Total_RFQ', 'size'), ('Done_RFQ', lambda x: x.eq('Done').sum())]
df=df.groupby(['display_name','security_type1','currency_str'])['state'].agg(d).reset_index()
df['Done_Pct'] = df['Done_RFQ'] / df['Total_RFQ'] * 100
print (df)
display_name security_type1 currency_str Total_RFQ Done_RFQ Done_Pct
0 A GOVT USD 1 1 100.0
1 B CORP NZD 1 0 0.0
2 B CORP USD 1 1 100.0
3 C CORP EUR 2 1 50.0
4 C CORP GBP 2 2 100.0
5 C CORP USD 1 1 100.0
如果需要检查子字符串:
d = [('Total_RFQ', 'size'), ('Done_RFQ', lambda x: x.str.contains('Done').sum())]
df=df.groupby(['display_name','security_type1','currency_str'])['state'].agg(d).reset_index()
df['Done_Pct'] = df['Done_RFQ'] / df['Total_RFQ'] * 100
print (df)
display_name security_type1 currency_str Total_RFQ Done_RFQ Done_Pct
0 A GOVT USD 1 1 100.0
1 B CORP NZD 1 0 0.0
2 B CORP USD 1 1 100.0
3 C CORP EUR 2 1 50.0
4 C CORP GBP 2 2 100.0
5 C CORP USD 1 1 100.0
【讨论】:
有效!! state 列可以包含我们想要包含的“Done”和“Tied Done”。看来 .contains 方法不可用。可以将 x.eq 更新为什么以包含任何带有“完成”的字符串? @PeterLucas - 这取决于需要什么,如果需要检查子字符串更好的是x.str.contains('Done').sum()
,如果需要检查字符串x.eq('Done').sum()
【参考方案2】:
这是一种方法。类似于@jezrael 的解决方案,但保留您的逻辑来检查子字符串Done
并过滤Done_RFQ > 0
。
另外,我相信你需要2次groupby
计算才能得到你想要的结果,即Total_RFQ
是由display_name
计算的。
# function to calcuate Done_RFQ
d = 'Done_RFQ': lambda x: x.str.contains('Done', na=False, regex=False).sum()
# apply 2 groupby calculations
df['Total_RFQ'] = df.groupby('display_name')['display_name'].transform('size')
group_cols = ['display_name', 'security_type1', 'currency_str', 'Total_RFQ']
res = df.groupby(group_cols)['state'].agg(d).reset_index()
# calculate Done_Pct
res['Done_Pct'] = res['Done_RFQ'] / res['Total_RFQ']
# filter for Done_RFQ > 0
res = res[res['Done_RFQ'] > 0]
print(res)
display_name security_type1 currency_str Total_RFQ Done_RFQ Done_Pct
0 A GOVT USD 1 1 1.0
2 B CORP USD 2 1 0.5
3 C CORP EUR 5 1 0.2
4 C CORP GBP 5 2 0.4
5 C CORP USD 5 1 0.2
【讨论】:
以上是关于Pandas Groupby:同一列上的聚合,但总计基于两个不同的标准/数据框的主要内容,如果未能解决你的问题,请参考以下文章
pyspark:groupby 和聚合 avg 和 first 在多个列上
提高性能(矢量化?) pandas.groupby.aggregate