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

如何自动化实现按消费总额均等划分客户Decile(十分位)

问题描述

我有一张交易数据表,包含Customer_ID(客户ID)和order_cost(订单金额)字段,记录了数千条随机排序的交易数据:

Customer_ID(客户ID)order_cost(订单金额)
1$503
53$7
4$80
13$76
6$270
78$2
8$45
910$89
10$3
1130$43
etc...etc...

我需要按Customer_ID分组,聚合所有订单金额得到spending(消费总额)列,然后新增Decile(十分位)字段,为每个客户分配1-10的编号,要求每个Decile内所有客户的spending总和占总消费的10%。预期结果表结构如下:

Customer_ID(客户ID)spending(消费总额)Decile(十分位)
45$5001
3$7001
349$8001
23$1,0001
64$2,0001
718$2,1001
3452$2,3001
1276$2,6002
10$3,0002
34$4,0002
etc...etc...etc...

目前我已通过PySpark实现分组聚合,用ntile(5000)对客户按spending升序分区,再手动配置when语句划分Decile,但手动试错太耗时,想找自动化实现该均等十分位划分的方法。现有代码如下:

import pyspark.sql.functions as F
import pyspark.sql.window as W

deciles = (table
                .groupBy('Customer_ID')
                .agg(F.sum('order_cost').alias('spending'))
                .withColumn('rank', F.ntile(5000).over(W.Window.partitionBy().orderBy(F.asc('spending')))) 
                .withColumn('rank', F.when(F.col('rank')<=4628, F.lit(1))
                                     .when(F.col('rank')<=4850, F.lit(2))
                                     .when(F.col('rank')<=4925, F.lit(3))
                                     .when(F.col('rank')<=4965, F.lit(4))
                                     .when(F.col('rank')<=4980, F.lit(5))
                                     .when(F.col('rank')<=4987, F.lit(6))
                                     .when(F.col('rank')<=4993, F.lit(7))
                                     .when(F.col('rank')<=4997, F.lit(8))
                                     .when(F.col('rank')<=4999, F.lit(9))
                                     .when(F.col('rank')<=5000, F.lit(10))
                                     .otherwise(F.lit(0)))
           )

end_table = (table.alias('a').join(deciles.alias('b'), ['Customer_ID'], 'left')
            .selectExpr('a.*', 'b.rank')
             )
自动化实现方案

要实现按消费总额占比划分均等十分位,核心是计算累计消费占比,再根据占比区间自动分配Decile编号,无需手动调整阈值。步骤如下:

  1. 预处理订单金额:移除order_cost中的$和逗号,转换为数值类型,避免聚合时出错。
  2. 计算客户消费总额:按Customer_ID分组求和得到spending。
  3. 计算全局总消费与累计占比:按消费降序排序(高消费客户优先),计算累计消费占总消费的比例。
  4. 自动分配Decile:根据累计占比区间直接映射到1-10的十分位编号。

完整代码如下:

import pyspark.sql.functions as F
import pyspark.sql.window as W

# 1. 清洗订单金额,转换为数值类型
clean_table = table.withColumn(
    'order_cost_num',
    F.regexp_replace(F.col('order_cost'), '[$,]', '').cast('double')
)

# 2. 计算每个客户的消费总额
customer_spending = clean_table.groupBy('Customer_ID').agg(
    F.sum('order_cost_num').alias('spending')
)

# 3. 计算全局总消费,同时按消费降序计算累计消费及占比
window_spec = W.Window.orderBy(F.desc('spending'))
total_spending = customer_spending.select(F.sum('spending').alias('total')).collect()[0]['total']

deciles_auto = customer_spending.withColumn(
    'cumulative_spending',
    F.sum('spending').over(window_spec)
).withColumn(
    'cumulative_percent',
    F.col('cumulative_spending') / total_spending
).withColumn(
    'Decile',
    F.floor(F.col('cumulative_percent') * 10) + 1  # 0-10%→1,10-20%→2...90-100%→10
)

# 4. 关联回原表得到最终结果
end_table_auto = table.alias('a').join(
    deciles_auto.alias('b'),
    on='Customer_ID',
    how='left'
).select(
    'a.*',
    'b.spending',
    'b.Decile'
)

关键说明

  • 预处理步骤确保金额为数值类型,避免字符串求和错误。
  • 按消费降序排序是因为高消费客户数量少但贡献占比高,能保证每个Decile的总消费占比更接近10%。
  • 累计占比乘以10后取整加1,自动完成区间映射,无需手动调整阈值。
  • 若存在多个客户消费总额相同导致累计占比跨区间的情况,PySpark会将这些客户分到同一个Decile,保证分组合理性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:30:49