如何在Polars中基于前一行值高效计算新列?
在Polars中高效实现依赖前一行值的列计算(替代map_rows)
针对你需要计算依赖前一行结果的Event列的需求,用map_batches替代map_rows是最符合Polars风格且高效的解决方案,以下是具体实现和说明:
核心实现代码
import polars as pl import numpy as np def calculate_event(time_series: pl.Series, minutes_series: pl.Series) -> pl.Series: # 转换为numpy数组以提升循环效率 t = time_series.to_numpy() m = minutes_series.to_numpy() event = np.empty_like(t) # 设置初始值:第一行的Event值按规则取t[0]+m[0] event[0] = t[0] + m[0] # 批量循环计算后续行 for i in range(1, len(t)): if t[i] > event[i-1]: event[i] = event[i-1] else: event[i] = t[i] + m[i] return pl.Series(event, dtype=pl.Float64) # 应用到DataFrame df = df.with_columns( pl.struct(["Time", "Minutes"]) .map_batches(lambda s: calculate_event(s["Time"], s["Minutes"])) .alias("Event") )
为什么这个方案比map_rows高效?
map_rows是逐行调用Python函数,每一行都有函数调用的开销,数据量越大效率越低;map_batches是按批处理整个列数据,一次性将整列(或分块)传入函数,配合numpy数组的底层优化,循环效率比逐行处理提升几个数量级。
补充说明
- 初始值调整:如果第一行的
Event值需要特殊规则,直接修改event[0]的赋值即可; - 超大规模数据:如果数据量达到千万级以上,还可以考虑用Polars的Rust UDF进一步优化,但上述方案对绝大多数场景已经足够高效;
- 类型适配:如果你的
Time和Minutes是整数类型,可将dtype=pl.Float64改为对应整数类型(如pl.Int64)。
内容的提问来源于stack exchange,提问作者Andres Rodriguez
相关产品推荐
相关产品推荐

