基于目标变量分桶:如何按贡献度将DSA随机划分为10个占比约10%的组
解决方案
核心思路
采用随机打乱+贪心凑数的逻辑,既保证分组的随机性,又能严格控制每组贡献的误差范围,全程无硬编码的固定阈值或列名,切换分组依据(3M/6M贡献)仅需修改传参即可,适配性极强。
前置依赖
仅需安装pandas和numpy两个通用数据处理库。
完整实现代码
1. 数据预处理
import pandas as pd import numpy as np # 示例数据,实际使用时替换为你的数据集读取代码(比如pd.read_csv) df = pd.DataFrame({ "DSA": ["ABC", "BCA", "CDE", "DCA", "EDA"], "3M Contribution": ["1.3%", "3.4%", "0.8%", "0.1%", "2%"], "6M Contribution": ["3.6%", "1.5%", "0.1%", "2%", "0.7%"] }) # 百分比列统一转数值格式,方便后续计算 for col in ["3M Contribution", "6M Contribution"]: df[col] = df[col].str.replace("%", "").astype(float) / 100
2. 通用分组函数
def random_contribution_group(df, contrib_col, group_num=10, error_tolerance=0.005): """ 按指定贡献列随机拆分分组 参数: df: 原始数据集 contrib_col: 用于计算分组贡献的列名,可传入"3M Contribution"或"6M Contribution" group_num: 拆分的组数,默认10 error_tolerance: 每组贡献允许的误差范围,默认0.005对应±0.5% """ # 全量随机打乱数据集,保证分组随机性 shuffled_df = df.sample(frac=1, random_state=None).reset_index(drop=True) # 计算单组目标贡献值,默认10组对应单组目标10% target_per_group = 1 / group_num groups = [] current_group = [] current_sum = 0.0 for _, row in shuffled_df.iterrows(): current_contrib = row[contrib_col] # 加入当前行后不超过误差上限则加入当前组 if current_sum + current_contrib <= target_per_group + error_tolerance: current_group.append(row.to_dict()) current_sum += current_contrib # 达到误差下限则闭合当前组,开启新组 if current_sum >= target_per_group - error_tolerance: groups.append(pd.DataFrame(current_group)) current_group = [] current_sum = 0.0 else: # 加入后超出上限则闭合当前组,当前行归入下一组 groups.append(pd.DataFrame(current_group)) current_group = [row.to_dict()] current_sum = current_contrib # 处理剩余未分组的行,合并到最后一组 if current_group: if groups: groups[-1] = pd.concat([groups[-1], pd.DataFrame(current_group)], ignore_index=True) else: groups.append(pd.DataFrame(current_group)) # 给每组打标签 for group_id, group_df in enumerate(groups, 1): group_df["group_id"] = group_id return pd.concat(groups, ignore_index=True)
3. 调用示例
# 按3M贡献分组 result_3m = random_contribution_group(df, "3M Contribution") # 按6M贡献分组,仅需修改contrib_col参数即可 result_6m = random_contribution_group(df, "6M Contribution") # 验证分组结果是否符合误差要求 print("3M贡献分组统计:") print(result_3m.groupby("group_id")["3M Contribution"].sum().round(4) * 100)
注意事项
- 如需固定分组结果方便复现,可将
sample方法中的random_state参数设置为固定整数,比如random_state=42。 - 180个DSA的场景下几乎每次运行都能得到符合误差要求的结果,若偶发误差超标,重新运行一次即可。
- 所有核心参数(组数、误差范围、分组依据)均支持自定义调整,无需修改内部逻辑。
内容的提问来源于stack exchange,提问作者rak953
相关产品推荐
相关产品推荐

