使用Polars按ID补全日期间隙(上采样)并填充缺失值的咨询
解决方案
步骤概述
- 将字符串类型的
date列转换为Polars日期类型,确保日期运算的准确性。 - 获取数据集全局的最小和最大日期,确定需要填充的完整日期区间。
- 生成包含所有唯一
id与完整日期序列的笛卡尔积表,覆盖每个id的全量日期行。 - 通过左连接合并原始数据与笛卡尔积表,将缺失的
sales值填充为0。
完整代码实现
import polars as pl df = pl.from_repr(""" ┌─────┬────────────┬───────┐ │ id ┆ date ┆ sales │ │ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ f64 │ ╞═════╪════════════╪═══════╡ │ 1 ┆ 2023-01-01 ┆ 10.0 │ │ 1 ┆ 2023-02-01 ┆ 20.0 │ │ 1 ┆ 2023-03-01 ┆ 30.0 │ │ 1 ┆ 2023-05-01 ┆ 40.0 │ │ 2 ┆ 2023-02-01 ┆ 50.0 │ │ 2 ┆ 2023-03-01 ┆ 60.6 │ │ 2 ┆ 2023-04-01 ┆ 70.2 │ │ 3 ┆ 2023-01-01 ┆ 80.5 │ │ 3 ┆ 2023-02-01 ┆ 90.0 │ └─────┴────────────┴───────┘ """) # 1. 转换日期列类型为Polars日期格式 df = df.with_columns(pl.col("date").str.to_date()) # 2. 获取全局最小/最大日期 min_date = df.select(pl.col("date").min()).item() max_date = df.select(pl.col("date").max()).item() # 3. 生成所有id与完整日期的笛卡尔积 full_dates = pl.date_range(start=min_date, end=max_date, interval="1d").alias("date") unique_ids = df.select(pl.col("id").unique()) full_frame = unique_ids.cross_join(full_dates) # 4. 左连接原始数据并填充缺失销售额为0 result = full_frame.join(df, on=["id", "date"], how="left").with_columns( pl.col("sales").fill_null(0.0) ).sort(["id", "date"]) print(result)
代码说明
- 日期类型转换:
str.to_date()将字符串格式的日期转为Polars原生日期类型,避免字符串操作带来的误差。 - 全局日期范围:通过
min()和max()获取整个数据集的日期边界,确保所有id都覆盖相同的完整日期区间。 - 笛卡尔积生成:
cross_join将每个唯一id与完整日期序列配对,直接得到每个id需要的全量日期行,无需按id单独循环处理。 - 左连接与填充:左连接保留全量日期行,
fill_null(0.0)自动将原始数据中未匹配到的日期对应的销售额填充为0。
替代方案(分组处理)
如果偏好按id分组逻辑处理,可使用group_by().apply()实现,但该方案在大数据集下性能弱于笛卡尔积+左连接的方式:
result = df.group_by("id").apply( lambda grp: pl.date_range(start=min_date, end=max_date, interval="1d") .to_frame("date") .with_columns( id=grp["id"].first(), sales=pl.col("date").map_elements( lambda d: grp.filter(pl.col("date") == d).select("sales").item() if not grp.filter(pl.col("date") == d).is_empty() else 0.0, return_dtype=pl.Float64 ) ) ).explode(["date", "sales"]).sort(["id", "date"])
内容的提问来源于stack exchange,提问作者nam0_0
相关产品推荐
相关产品推荐

