如何在Pandas中按分组用最大余数法处理权重列使合计为100%
问题:Pandas分组应用最大余数法调整权重至合计100%(两位小数)
需求说明
- 按
Name字段分组,对每组的Weight列应用最大余数法(Largest Remainder Method) - 处理后的值保留两位小数,且每组的
New Weight列合计为100%
输入DataFrame
import pandas as pd df = pd.DataFrame({ 'Name': ['John', 'John', 'John', 'James', 'James', 'James', 'Kim', 'Kim', 'Jane', 'Jane', 'Jane'], 'Weight': [33.3333, 33.3333, 33.3333, 50, 25, 25, 6.6666, 93.3333, 46.6666, 6.6666, 46.6666] }) print(df)
输出:
Name Weight 0 John 33.3333 1 John 33.3333 2 John 33.3333 3 James 50.0000 4 James 25.0000 5 James 25.0000 6 Kim 6.6666 7 Kim 93.3333 8 Jane 46.6666 9 Jane 6.6666 10 Jane 46.6666
预期结果
Name Weight New Weight 0 John 33.3333 33.33 1 John 33.3333 33.33 2 John 33.3333 33.34 3 James 50.0000 50.00 4 James 25.0000 25.00 5 James 25.0000 25.00 6 Kim 6.6666 6.66 7 Kim 93.3333 93.34 8 Jane 46.6666 46.66 9 Jane 6.6666 6.67 10 Jane 46.6666 46.67
用户尝试的代码及问题
用户已实现round_to_100_percent函数(最大余数法)和自定义explode函数,但在分组应用后合并数据时出现以下问题:
- 合并后生成多余的
Weight_y列 - 部分场景下行数超过原DataFrame
尝试代码:
new_column = df.groupby('Name')['Weight'].apply(round_to_100_percent) # Merge new_column into main data frame df = pd.merge(df, new_column, on='Name', how='outer') # For some reason _y is added to col df = df.explode('Weight_y') df['New Weight'] = df['Weight_y']*0.01
优化解决方案
无需自定义explode函数,直接利用Pandas的groupby.transform方法,自动将分组计算结果映射回原DataFrame对应行,避免合并和展开的麻烦:
步骤1:保留原最大余数法函数
def round_to_100_percent(number_set, digit_after_decimal=2): unround_numbers = [x / sum(number_set) * 100 * 10 ** digit_after_decimal for x in number_set] decimal_part_with_index = sorted( [(index, unround_numbers[index] % 1) for index in range(len(unround_numbers))], key=lambda y: y[1], reverse=True ) remainder = 100 * 10 ** digit_after_decimal - sum([int(x) for x in unround_numbers]) index = 0 while remainder > 0: unround_numbers[decimal_part_with_index[index][0]] += 1 remainder -= 1 index = (index + 1) % len(number_set) return [int(x) / (10 ** digit_after_decimal) for x in unround_numbers]
步骤2:应用transform生成新列
# 直接用transform将分组计算结果映射回原行 df['New Weight'] = df.groupby('Name')['Weight'].transform(round_to_100_percent) # 可选:确保显示两位小数(不影响数值精度) df['New Weight'] = df['New Weight'].round(2) print(df)
说明
groupby.transform会对每个分组执行函数,并将结果按原DataFrame的索引对齐,直接生成与原表行数一致的新列- 无需额外合并、展开操作,避免了多余列和行数异常的问题
- 原函数逻辑保持不变,确保最大余数法的正确性
内容的提问来源于stack exchange,提问作者bbaskets
相关产品推荐
相关产品推荐

