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

如何在Polars Lazy DataFrame中不用apply/map实现分组cut并支持sink_parquet?

问题:Polars Lazy DataFrame替代groupby+apply实现分箱操作

现有Polars Eager模式代码通过groupby结合apply方法,对x列按指定bins进行分箱(cut)并合并结果。但在Lazy DataFrame场景下使用apply或map方法后,执行sink_parquet会触发报错:

PanicException: sink_parquet not yet supported in standard engine.

目标是扫描大型CSV文件、完成转换后用sink_parquet写入,因此需要改用不依赖apply/map的Lazy模式实现相同功能。

原Eager模式代码示例:

import numpy as np
import polars as pl

def cut(_df):
    _c = _df['x'].cut(bins).with_columns([pl.col('x').cast(pl.Int64)])
    final = _df.join(_c, left_on='x', right_on='x')
    return final

groups = ["A"]*500 + ["B"]*500
bins = [0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]
x = np.arange(0,1000)
np.random.shuffle(x)
df = pl.DataFrame({"x":x,"group":groups})
with pl.StringCache():
    res = df.groupby("group").apply(cut)

解决方案

原代码中groupby.apply(cut)的操作实际是冗余的——因为cut是基于全局固定的bins对x值进行分箱,和分组无关。直接在Lazy模式下对x列调用cut方法,即可生成对应的分箱列,无需分组处理。

具体实现代码:

import numpy as np
import polars as pl

# 定义分箱边界
bins = [0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000]

# Lazy模式处理流程
(
    pl.scan_csv("large_input.csv")  # 扫描大型CSV
    .with_columns(
        # 对x列执行分箱,直接生成break_point和category列
        pl.col("x").cut(bins).alias("cut_result")
    )
    # 展开分箱结果的结构体列
    .unnest("cut_result")
    # 写入Parquet文件
    .sink_parquet("output.parquet")
)

关键说明:

  • pl.col("x").cut(bins)会直接返回一个结构体列,包含break_point和category两个字段,用unnest可以将其展开为独立列,和原Eager代码的结果完全一致。
  • 整个流程全程使用Lazy API,没有使用apply/map,因此可以正常调用sink_parquet写入大型文件,避免了引擎不支持的报错。
  • 如果确实需要按分组独立定义bins(原问题中bins是全局的,此场景为扩展),可以预先将分组对应的bins存入字典,通过map_dict结合cut实现,但原问题中无需此操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 03:05:32