如何用Pandas按供应商与周计算通过率并生成含对应列的新DataFrame?
问题描述
现有如下结构的DataFrame:
Vendor GRDate Pass/Fail 0 204177 2022-22 1.0 1 204177 2022-22 0.0 2 204177 2022-22 0.0 3 204177 2022-22 1.0 4 204177 2022-22 1.0 5 204177 2022-22 1.0 7 201645 2022-22 0.0 8 201645 2022-22 0.0 9 201645 2022-22 1.0 10 201645 2022-22 1.0
需求:按Vendor和GRDate分组,计算每组中Pass/Fail等于1的通过率(通过数/总条数),生成包含Vendor、GRDate、Performance列的新DataFrame,预期结果如下:
Vendor GRDate Performance 0 204177 2022-22 0.6 1 201645 2022-22 0.5
尝试的代码如下:
sdp_percent = sdp.groupby(['GRDate','Vendor'])['Pass/Fail'].apply(lambda x: x[x == 1].count()) / sdp.groupby(['GRDate','Vendor'])['Pass/Fail'].count()
遇到的问题:
- 上述代码仅返回通过率数值,
Vendor和GRDate作为索引存在而非显式列,看起来像是丢失了; - 若给两个groupby结果都添加
.reset_index(),会报错:unsupported operand type(s) for /: 'str' and 'str'
问题分析与解决
问题根源
- 两次独立执行
groupby后做除法,得到的是带MultiIndex的Series:GRDate和Vendor是索引层级,不是显式列,所以看起来像是丢失了这两列; - 若给两个groupby结果都执行
reset_index(),会得到两个包含GRDate、Vendor、Pass/Fail列的DataFrame,此时做除法会尝试对所有列进行运算——但GRDate和Vendor是字符串类型,无法参与除法,因此触发类型错误。
正确实现方式
方法1:利用均值直接计算(最简洁)
由于Pass/Fail列是1(通过)和0(失败)的数值型数据,分组后的均值恰好等于通过率(通过数/总条数),写法如下:
sdp_percent = sdp.groupby(['GRDate', 'Vendor'])['Pass/Fail'].mean().reset_index(name='Performance')
方法2:单次groupby内完成计算
通过apply在分组内一次性计算通过率,避免两次groupby的冗余操作:
sdp_percent = sdp.groupby(['GRDate', 'Vendor'])['Pass/Fail'].apply(lambda x: x[x == 1].count() / len(x)).reset_index(name='Performance')
方法3:使用agg聚合函数
通过agg分别统计通过数和总数,再计算比率:
agg_result = sdp.groupby(['GRDate', 'Vendor'])['Pass/Fail'].agg( pass_count=lambda x: x[x == 1].count(), total_count='count' ).reset_index() sdp_percent = agg_result.assign(Performance=agg_result['pass_count'] / agg_result['total_count'])[['Vendor', 'GRDate', 'Performance']]
以上三种方法均可得到符合预期的DataFrame,其中方法1最为高效简洁。
内容的提问来源于stack exchange,提问作者jhew123
相关产品推荐
相关产品推荐

