如何在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
相关产品推荐
相关产品推荐

