2 亿行明细、100 个候选维度,如何做大数据归因?

📅 2026/7/29 16:10:03
2 亿行明细、100 个候选维度,如何做大数据归因?
作者铭新在指标分析场景中我们经常会遇到这样的问题为什么这个月销售额下降了到底是哪个地区、渠道、商品类型或客户群体导致的当数据量不大、候选维度较少时可以直接使用 Python 做归因分析。但当场景升级到单分区约 2 亿行明细数据候选维度接近 100 个最终还要输出清晰、可解释的归因结果问题就不再只是选择哪种算法而是如何控制计算规模。我们的核心思路是不让 Python 直接处理全量明细而是在数据库侧先完成维度筛选和数据聚合最后只把少量有效数据交给 Python 精算。一、为什么不能直接对 100 个维度做归因最直接的方式是将 100 个维度全部进行组合聚合再交给 Python 分析。但这种方式在大数据场景下几乎不可行。首先维度组合数量会快速膨胀。即使每个维度只有少量维值多个维度组合后也可能产生巨大的结果集。其次一些维度虽然字段可用但并不适合归因例如用户 ID订单号手机号流水号设备 ID。这类字段通常接近一行一个值只能定位具体记录难以形成具有业务意义的结论。相比之下浙江地区线上家电销售额下降 120 万。显然比用户 100023 导致销售额下降 500 元。更容易理解也更具行动价值。因此在大数据归因中必须先解决两个问题哪些维度值得进入归因如何把数据规模压缩到 Python 可以承载的范围。二、总体思路SQL 做筛选Python 做精算整体流程可以概括为100 个候选维度 ↓ 拆分预设维度和待筛选维度 ↓ 过滤无效、高基维度 ↓ 计算单维波动解释能力 ↓ 通过类似树模型 Gain 的方式继续剪枝 ↓ 选出最终 15 个维度 ↓ 数据库聚合两期数据 ↓ Python 执行最终归因不同技术层的职责也很清晰执行层主要职责数据库维度过滤、候选筛选、数据聚合Java 服务复用平台取数口径、组织任务、传递指标总值PythonShapley、TreeSHAP、贡献计算和 TopN 输出核心原则是数据库负责降规模Python 负责高价值计算。三、预设维度优先保护实际生产中通常已经存在一些业务确认过的常用维度例如省份城市商品类型渠道客户类型。这些维度有明确的业务价值不应因为某一次数据分布变化就被轻易过滤。因此首先将维度拆分为两类预设维度业务确认需要优先保留的维度 待筛选维度其他候选维度最终目标是选择 15 个维度。处理规则如下预设维度少于 15 个时全部保留其余名额由算法补齐预设维度正好为 15 个时直接使用预设维度超过 15 个时只在预设维度中选出最终 15 个。这样既保留了业务经验也避免了维度数量失控。四、第一轮筛选过滤无效和高基维度对于非预设维度首先计算数据总行数近似去重数去重数占比空值率。然后过滤明显不适合归因的字段。例如条件处理只有一个维值剔除空值率过高剔除去重数接近总行数剔除典型被过滤的字段包括用户 ID订单号流水号设备 ID。高基维度需要提前过滤主要有几个原因单个维值样本太少结果容易受偶然波动影响归因结果会被拆成大量细小切片最终结果难以阅读和解释多维组合后聚合数据规模难以控制树模型的重要性可能偏向高基特征。完成硬性过滤后再按照维度基数和配置比例保留部分候选维度。这一阶段的目标是约 100 个候选维度 → 3050 个有效候选维度五、第二轮筛选评估单维波动解释能力仅靠基数无法判断一个维度是否真正有价值。例如一个维度基数很低但它可能与指标变化几乎没有关系。因此需要分别从每个维度观察基期和对比期的变化。以“省份”为例省份基期销售额对比期销售额变化浙江200 万80 万-120 万江苏150 万90 万-60 万上海100 万130 万30 万通过这些结果可以判断一个维度能解释多少整体波动主要变化是否集中在少数维值变化方向是否与整体趋势一致。然后为每个维度生成一个综合评分。评分高的维度通常具备以下特点对整体变化解释能力强头部原因比较清晰与整体变化方向一致结果更容易被业务理解。这一阶段完成后将候选维度进一步压缩到约 2025 个。六、第三轮筛选减少维度之间的信息重复单维评分只能判断每个维度单独是否有效但不能判断不同维度之间是否重复。例如省份和大区城市和城市等级商品类型和商品大类。这些维度可能都得到较高评分但表达的信息高度相似。因此可以借鉴 GBDT、LightGBM 的思路每一轮选择一个最能解释当前剩余波动的维度选中后扣除它已经解释的部分再选择下一个维度。假设第一轮选择了“省份”。省份解释掉一部分销售额变化后下一轮会基于剩余未解释部分重新计算。如果“大区”和省份高度相关它的价值就会下降而“商品类型”如果能够解释另一部分变化则仍可能被选中。通过多轮选择可以降低最终维度之间的信息冗余。需要强调的是这里并不是在 SQL 中完整实现 LightGBM而是借鉴树模型的分裂收益和残差迭代思想用于维度剪枝。最终目标是从约 2025 个候选维度中选出最有价值的 15 个。七、选出 15 个维度后再进行正式聚合维度选择完成后数据库重新按照平台现有取数逻辑生成基期和对比期的聚合数据。例如省份城市商品类型渠道基期值对比期值变化浙江杭州家电线上200 万80 万-120 万江苏南京家电线上150 万90 万-60 万上海上海数码线下100 万130 万30 万这里必须继续复用平台原有取数口径包括指标定义时间范围筛选条件下钻条件行级权限汇总规则。维度筛选过程只决定“选择哪些维度”不能改变正式指标口径。八、Python 只处理可控规模的聚合数据完成数据库侧剪枝后Python 接收到的是最终 15 个维度的聚合数据而不是 2 亿行明细。Python 侧主要负责Shapley 或 TreeSHAP 归因多维切片贡献计算正向和反向贡献拆分TopN 排序贡献率计算结果 JSON 输出。最终结果可以是导致指标下降的主要原因排名切片贡献值占整体下降1浙江 杭州 家电 线上-120 万40%2江苏 南京 家电 线上-60 万20%抵消整体下降的因素排名切片贡献值抵消比例1上海 数码 线下30 万10%这样既保留了算法能力也保证了结果的业务可读性。九、非可加指标需要特别处理对于销售额、订单金额等可加指标可以通过聚合数据求和得到整体值。但对于以下指标去重用户数平均值转化率留存率比例类指标不同切片之间通常不能简单相加。因此基期总值和对比期总值必须由平台现有取数逻辑提供并传给 Python。Python 可以负责贡献分配但最终占比的分母仍使用平台权威总值。这样可以避免归因结果与看板展示口径不一致。十、从 100 个维度到 15 个维度以销售额归因为例候选维度100 个 预设维度省份、城市、商品类型 基期销售额1000 万 对比期销售额700 万 整体下降300 万处理过程如下100 个候选维度 → 剔除用户 ID、订单号、手机号等高基字段 → 保留约 42 个有效维度 → 单维评分后保留 25 个 → 已有 3 个预设维度 → 再从候选维度中选出 12 个 → 最终得到 15 个维度最终维度可能包括省份、城市、商品类型、渠道、门店类型、 品牌、供应商、客户类型、会员等级、订单类型、 支付方式、活动类型、终端类型、销售组织、业务线再由 Python 输出最终归因结果。十一、这套方案解决的核心问题这套方案真正解决的并不只是算法问题而是大数据归因的工程落地问题如何避免 Python 直接处理全量明细如何过滤无业务价值的维度如何控制维度组合规模如何减少重复维度如何保证归因口径与平台查询一致如何处理非可加指标如何让最终结果既准确又可解释。整个方案可以总结为一句话SQL 负责把问题缩小Python 负责把问题算准。对于 2 亿行数据和 100 个候选维度与其追求一次性完成全量计算不如先通过数据库完成分层筛选再将真正有价值的数据交给算法。这也是大数据归因从“算法实验”走向“生产能力”的关键。