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

pandas客户三等分分箱分组不均问题的代码优化咨询

问题根因

你当前代码分组客户数不均的核心原因有两点:

  • 现有逻辑先计算Ea EUR(即入参expo)列的1/3、2/3分位点作为切分阈值,再通过pd.cut()按取值打组,在Ea EUR存在大量重复值时会出现严重偏差:如果分位点位置刚好对应大批同值记录,这些记录会被全部分到同一侧分组,直接打破等人数要求。比如总客户300个,1/3分位点取值为500,但有80个客户的Ea EUR都是500,这80个客户会全被划入Lower组,最终Lower组人数会达到180,远高于100的预期值。
  • 现有逻辑本质是按Ea EUR取值区间做等频切分,不是按客户排序后的位次做三等分,只要存在取值重复,两种逻辑的结果就会出现偏差。
修正方案

替换原有按值切分的打组逻辑,改为排序后按位次分组,从根源避免重复值带来的偏移:

  1. 先按Ea EUR列对筛选后的客户做升序排序,重置索引保证索引连续
  2. 以排序后的索引为依据做切分,直接把客户划分为人数完全均等的三个组,最大程度保证同组客户的Ea EUR取值接近
  3. 保留原有聚合、指标计算逻辑,仅替换分组打标部分,同时补全原有代码的隐式警告、分组缺失类别的问题
修正后完整代码
import pandas as pd
import numpy as np
from scipy import stats

def f(df, stab, idn, ndef, expo, pdm, segm):       
    # 加copy避免链式赋值警告
    df = df.loc[df[stab] == segm].copy()
    df = df.sort_values(by=[expo]).reset_index(drop=True)
    total_client = len(df)
    # 按排序后的索引切分,三组客户数差不超过1,完全满足等人数要求
    df['By ex'] = pd.cut(
        df.index,
        bins=[-1, total_client//3, total_client*2//3, total_client],
        labels=['Lower', 'Medium', 'Upper']
    )

    dfA = df.groupby(['By ex'], observed=False).agg(
        apd = (pdm, 'mean'), 
        ncl=(idn, 'count'), 
        ndf=(ndef, 'sum'),
        ex=(expo, 'sum')
    )
    dfA.loc[:, 'dfr'] = dfA['ndf'] / dfA['ncl']   
    dfA.loc[:, 'p_value'] = stats.beta.cdf(
        dfA['apd'],
        dfA['ndf'] + 1/2,
        dfA['ncl'] - dfA['ndf'] + 1/2
    )
    dfA = dfA.reset_index()
    dfA = dfA.rename({
        'ncl':'N', 
        'ndf':'D',
        'ex':'Ea EUR',
        'dfr':'DR', 
        'p_value':'test p-value'
    }, axis=1)
    df_temp = pd.DataFrame({
        "Ex tertile" : dfA.loc[:, "By ex"].values,
        "Ea EUR" : dfA.loc[:, "Ea EUR"].values,
        "AD" : dfA.loc[:, "apd"].values,
        "N" : dfA.loc[:, 'N'].values,
        "D" : dfA.loc[:, "D"].values,
        "DR" : dfA.loc[:, "DR"].values,
        "test p-value" : dfA.loc[:, "test p-value"].values
    })
    # 原np.vstack逻辑会把所有数值转成字符串,需要保留数值类型可直接return df_temp
    return pd.DataFrame(np.vstack([df_temp.columns, df_temp]))
可选调整项
  • 如果业务要求Ea EUR取值相同的客户必须分到同一个组,可以把打组逻辑替换为按秩分组:先计算df['ex_rank'] = df[expo].rank(method='min'),再按秩做三等分切分。这种方式会在存在大量同值时允许组间人数有小幅偏差,但能保证同值客户同组。
  • 如果不需要兼容原有返回格式,直接返回df_temp即可,不需要用np.vstack做拼接,避免数值类型被转成字符串影响后续计算。
  • 如果需要和原分位点切分逻辑的结果做对比,可以打印两种逻辑下每组的N值,验证人数均等效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 02:24:20