如何实现适配不同列名的DataFrame百分比计算通用函数?
解决方案
问题分析
原函数的核心问题:
- 函数内部定义了空的
cols局部变量,外部的列名列表无法传入,导致过滤指定列的逻辑完全无效。 - 分组列是硬编码的,后续修改分组规则时必须改动函数内部代码,扩展性差。
你改写的版本存在几个明显错误:
inner_function中cols = df.columns.difference(grouper)里的df未定义,应该替换为传入的DataFrame参数a。create_percent_column_many中遍历的dfs未定义,需要将传入的多个DataFrame转为列表。- 若不需要将结果转为长表(
melt操作),可移除该步骤以匹配原函数的宽表输出;若需要长表格式,需确保参数传递逻辑正确。
修正后的代码
版本1:保留原函数宽表输出格式
def process_single_df(df, grouper=None, cols=None): # 默认分组列与原函数保持一致 if grouper is None: grouper = ['Name', 'Type', 'Date'] # 未指定cols时,默认使用除分组列外的所有列 if cols is None: cols = df.columns.difference(grouper).tolist() # 计算分组后指定列中值为4的占比 result = (df.groupby(grouper)[cols] .agg(lambda x: x.eq(4).sum() / x.count()) .reset_index()) return result def create_percent_column_many(*dfs, grouper=None, cols=None): # 支持传入任意数量的DataFrame,扩展性更强 return [process_single_df(df, grouper, cols) for df in dfs] # 使用示例 # 场景1:手动指定列名和分组列 cols = ['Flames', 'Canucks', 'Oilers', 'Sharks', 'Wings', 'Chiefs'] grouper = ['Name', 'Type', 'Date'] new_a, new_b, new_c = create_percent_column_many(a, b, c, grouper=grouper, cols=cols) # 场景2:使用默认参数(分组列用默认值,cols自动取非分组列) new_a, new_b, new_c = create_percent_column_many(a, b, c) print(new_a)
版本2:转为长表格式(保留melt)
如果需要将宽表转为长表(每行对应一个列的占比数据),可修改process_single_df:
def process_single_df(df, grouper=None, cols=None): if grouper is None: grouper = ['Name', 'Type', 'Date'] if cols is None: cols = df.columns.difference(grouper).tolist() result = (df.groupby(grouper)[cols] .agg(lambda x: x.eq(4).sum() / x.count()) .reset_index() .melt(id_vars=grouper, value_vars=cols, var_name='Team', value_name='Percent_Equal_4')) return result # 使用方式与版本1一致 new_a, new_b, new_c = create_percent_column_many(a, b, c, cols=cols)
关键改进点
- 用
*dfs参数接受任意数量的DataFrame,后续新增数据集无需修改函数。 - 将分组列
grouper和计算列cols作为参数传入,后续修改列名或分组规则只需调整调用参数,无需改动函数内部代码。 - 为参数设置合理默认值,兼顾原有使用习惯和灵活扩展性。
- 修复了变量未定义的语法错误,确保逻辑可正常运行。
内容的提问来源于stack exchange,提问作者Skywalker5032
相关产品推荐
相关产品推荐

