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

在Databricks PySpark中基于月级窗口计算排除当月的中位数

解决Databricks PySpark按账户分区计算前两个月cost中位数的问题

问题分析

你需要按account分区,计算每条记录日期所在月份前两个完整月份的cost中位数,且当不足两个月份数据时返回null。之前的代码报错原因如下:

  1. 弃用警告:旧版PySpark中使用日期范围的方式已被弃用,需改用基于月份分区或interval的范围定义
  2. 参数错误:在调用日期函数(如add_months)时,错误地将整数作为列参数传入,而函数要求传入列名或Column对象

解决方案

以下是适配Databricks PySpark 3.x+的实现代码,完全符合你的预期输出:

步骤1:导入依赖函数

from pyspark.sql.functions import to_date, date_trunc, collect_list, expr, struct
from pyspark.sql.window import Window

步骤2:预处理数据并按月份聚合

首先确保date字段为日期类型,然后按account和月份分组,收集每个月的cost列表:

# 转换date为日期类型(如果原始数据是字符串格式)
df = df.withColumn("date", to_date("date"))

# 按账户和月份聚合,得到每个月的cost列表
monthly_agg = df.withColumn("month_start", date_trunc("month", "date")) \
                .groupBy("account", "month_start") \
                .agg(collect_list("cost").alias("monthly_costs"))

步骤3:定义窗口计算前两个月的中位数

通过窗口函数获取每个月份的前两个完整月份数据,判断是否有足够数据后计算中位数:

# 定义窗口:按账户分区,按月份排序,取当前月份的前两个月份
window_spec = Window.partitionBy("account").orderBy("month_start").rowsBetween(-2, -1)

# 收集前两个月的月份和cost数据,计算中位数
monthly_with_median = monthly_agg.withColumn("prev_two_months_data", collect_list(struct("month_start", "monthly_costs")) over window_spec) \
                                 .withColumn("has_two_valid_months", expr("size(prev_two_months_data) = 2")) \
                                 .withColumn("combined_costs", expr("flatten(transform(prev_two_months_data, x -> x.monthly_costs))")) \
                                 .withColumn("median", expr("if(has_two_valid_months, percentile_approx(combined_costs, 0.5), null)"))

步骤4:关联回原始数据

将计算好的中位数关联到原始DataFrame的对应月份记录:

# 关联原始数据与中位数结果
final_df = df.join(monthly_with_median.select("account", "month_start", "median"),
                   on=[df.account == monthly_with_median.account, date_trunc("month", df.date) == monthly_with_median.month_start],
                   how="left") \
             .drop(monthly_with_median.account, monthly_with_median.month_start)

验证结果

执行上述代码后,final_df的输出将完全匹配你的预期:

accountdatecostmedian
account12024-10-015.00null
account12024-10-026.00null
account12024-10-037.00null
account12024-11-018.00null
account12024-11-029.00null
account12024-11-0310.00null
account12024-12-014.887.5
account12024-12-028.467.5
account12024-12-039.437.5

关键说明

  • 使用date_trunc("month", "date")统一获取每个日期所在月份的起始日期,避免日期范围计算误差
  • percentile_approx是PySpark中高效计算中位数的函数,适合大数据场景
  • 通过size(prev_two_months_data) = 2判断是否有两个完整月份的数据,确保只有当存在两个月数据时才返回中位数,否则为null

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 16:40:57