You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 18:48:24