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

Polars DataFrame中slice表达式索引异常问题排查与解决

Polars分组切片行数不符合预期的问题解决

问题描述

我有一个Polars DataFrame,结构如下:

shape: (2_655_541, 4)
┌────────────┬────────────┬─────────────────┬─────────────────────┐
│ streamflow ┆ sm_surface ┆ basin_id        ┆ time                │
│ ---        ┆ ---        ┆ ---             ┆ ---                 │
│ f32        ┆ f32        ┆ str             ┆ datetime[μs]        │
╞════════════╪════════════╪═════════════════╪═════════════════════╡
│ null       ┆ null       ┆ camels_01022500 ┆ 2015-01-01 03:00:00 │
│ null       ┆ null       ┆ camels_01022500 ┆ 2015-01-01 06:00:00 │
│ null       ┆ null       ┆ camels_01022500 ┆ 2015-01-01 09:00:00 │
│ null       ┆ null       ┆ camels_01022500 ┆ 2015-01-01 12:00:00 │
│ null       ┆ null       ┆ camels_01022500 ┆ 2015-01-01 15:00:00 │
│ …          ┆ …          ┆ …               ┆ …                   │
│ 0.718293   ┆ 0.40595    ┆ HML_LOBO3       ┆ 2016-12-30 18:00:00 │
│ null       ┆ 0.40601    ┆ HML_LOBO3       ┆ 2016-12-30 21:00:00 │
│ null       ┆ 0.406075   ┆ HML_LOBO3       ┆ 2016-12-31 00:00:00 │
│ null       ┆ 0.406177   ┆ HML_LOBO3       ┆ 2016-12-31 03:00:00 │
│ null       ┆ 0.406333   ┆ HML_LOBO3       ┆ 2016-12-31 06:00:00 │
└────────────┴────────────┴─────────────────┴─────────────────────┘

我需要按basin_id分组后对每个分组切片,执行以下代码:

df1 = (valid_ds.y_origin.group_by('basin_id', maintain_order=True).agg(pl.all().slice(0, 2865)).explode(pl.exclude('basin_id')))

得到结果行数为2_604_285。但出现以下异常:

  • 将slice参数改为(1,2865)时,结果起始时间变化,但总行数未改变;
  • 改为slice(100,2865)时,结果行数变为2_564_641,计算得每个basin平均行数为2821,并非预期的2865-100=2765。

问题原因

Polars中的slice(offset, length)方法,第二个参数是要提取的行数,而非结束索引。具体来说:

  • slice(0,2865):从第0行开始,提取2865行;
  • slice(1,2865):从第1行开始,提取2865行;
  • slice(100,2865):从第100行开始,提取2865行。

你的异常源于对参数的误解:当你用slice(100,2865)时,你以为是取第100到2865行(共2765行),但实际是从第100行开始取2865行。如果某个分组的总行数≥100+2865,就会取满2865行;如果分组总行数不足,则只能取到分组末尾的所有行,这就导致最终平均行数低于预期的2765。

而slice(0,2865)和slice(1,2865)总行数不变,是因为大部分分组的总行数≥2865(slice(1,2865)仍能取到2865行),只有少数分组行数不足,但对总行数影响极小。

解决方法

根据你的需求(从第offset行开始,取2865 - offset行,即每个分组保留前2865行中的后2865-offset行),可以用以下两种方式调整:

方法1:先取前2865行,再从偏移量位置切片

先确保每个分组只保留前2865行,再从指定偏移量开始提取剩余行,这样能保证每个分组最多取2865 - offset行:

offset = 100
df1 = (
    valid_ds.y_origin
    .group_by('basin_id', maintain_order=True)
    .agg(pl.all().head(2865).slice(offset))  # 先取前2865行,再从第100行取到末尾
    .explode(pl.exclude('basin_id'))
)

方法2:明确指定切片长度为目标行数

直接将slice的第二个参数设置为2865 - offset,这样每个分组从偏移量开始取固定长度的行:

offset = 100
target_length = 2865 - offset
df1 = (
    valid_ds.y_origin
    .group_by('basin_id', maintain_order=True)
    .agg(pl.all().slice(offset, target_length))
    .explode(pl.exclude('basin_id'))
)

如果分组总行数不足offset + target_length,这种方式会取到分组末尾的所有行,符合多数水文数据处理的预期(避免补无效空值)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 13:24:58