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

按element和date分组归一化,确保6位小数和为1的实现方法

分组归一化后求和严格等于1的实现

需求:按element和date分组,对factor_a、factor_b字段做归一化处理并保留6位小数,且每组归一化后的数值和必须严格等于1。

原始数据与尝试代码

用户构建的DataFrame:

import pandas as pd

data = {'element': ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C', 'C'],
        'subelement': ['A1', 'A2', 'A3', 'B1','B2', 'B3','B4', 'B5','B5', 'B7', 'C1', 'C2', 'C3'],
        'date': ['2022-06-01', '2022-06-01', '2022-06-01', '2022-06-01', '2022-06-01', '2022-06-01',
                 '2022-06-01','2022-06-01', '2022-06-01', '2022-06-01','2022-07-01','2022-07-01','2022-07-01'],
        'factor_a': [0.333333333333333, 0.333333333333333, 0.333333333333333, 
                    0.142857142857143, 0.142857142857143, 0.142857142857143, 0.142857142857143,
                    0.142857142857143, 0.142857142857143, 0.142857142857143,
                   0.333333333333333, 0.333333333333333, 0.333333333333333],
        'factor_b': [0.65, 0.35, 0, 0.5, 0, 0.5, 0, 0, 0, 0, 0.333333333333333, 0.333333333333333, 0.333333333333333]
       }
df = pd.DataFrame(data)

用户尝试的代码存在误差问题:直接对归一化结果做round(6)会导致求和后出现0.999999或1.000001的偏差,无法严格等于1。

cols = df.columns[3:]
groups = df.groupby(['element', 'date'])[cols] 
sum_ = groups.transform('sum')
df[cols+'_norm'] = (df[cols] / sum_).round(6)

解决方案

核心思路:先计算保留6位小数的归一化初始值,再计算每组的求和误差,将误差调整到组内某一个元素上(这里选择组内最后一个元素,最小化对整体分布的影响),确保总和严格为1。

完整实现代码:

import pandas as pd

# 构建DataFrame
data = {'element': ['A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'C', 'C'],
        'subelement': ['A1', 'A2', 'A3', 'B1','B2', 'B3','B4', 'B5','B5', 'B7', 'C1', 'C2', 'C3'],
        'date': ['2022-06-01', '2022-06-01', '2022-06-01', '2022-06-01', '2022-06-01', '2022-06-01',
                 '2022-06-01','2022-06-01', '2022-06-01', '2022-06-01','2022-07-01','2022-07-01','2022-07-01'],
        'factor_a': [0.333333333333333, 0.333333333333333, 0.333333333333333, 
                    0.142857142857143, 0.142857142857143, 0.142857142857143, 0.142857142857143,
                    0.142857142857143, 0.142857142857143, 0.142857142857143,
                   0.333333333333333, 0.333333333333333, 0.333333333333333],
        'factor_b': [0.65, 0.35, 0, 0.5, 0, 0.5, 0, 0, 0, 0, 0.333333333333333, 0.333333333333333, 0.333333333333333]
       }
df = pd.DataFrame(data)

cols = df.columns[3:]
group_keys = ['element', 'date']

# 计算归一化后保留6位小数的初始值
sum_ = df.groupby(group_keys)[cols].transform('sum')
df[cols + '_norm'] = (df[cols] / sum_).round(6)

# 对每个归一化列进行误差修正
for col in cols:
    norm_col = f"{col}_norm"
    # 计算每组求和与1的误差
    group_sum = df.groupby(group_keys)[norm_col].transform('sum')
    error = 1 - group_sum
    # 获取每组最后一行的索引,将误差加到该行对应列
    last_row_idx = df.groupby(group_keys).tail(1).index
    df.loc[last_row_idx, norm_col] += error.loc[last_row_idx]
    # 再次保留6位小数,避免修正后出现多余小数位
    df[norm_col] = df[norm_col].round(6)

# 验证结果
print("factor_a_norm分组求和结果:")
print(df.groupby(group_keys)['factor_a_norm'].sum())
print("\nfactor_b_norm分组求和结果:")
print(df.groupby(group_keys)['factor_b_norm'].sum())

代码说明

  1. 先完成常规归一化并保留6位小数,得到初始归一化列。
  2. 对每个归一化列,计算每组求和与1的误差值。
  3. 将误差值加到每组最后一个元素上,再重新保留6位小数,确保总和严格为1。
  4. 可选优化:若不想调整最后一个元素,可选择组内数值最大的元素,进一步降低调整对数据分布的影响。

内容的提问来源于stack exchange,提问作者rfv18

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 06:55:22