如何在Python Polars中基于条件动态相乘列?
在Polars中基于动态年份列计算乘积
核心思路
先自动识别所有以年份数字命名的列,再通过向量化操作,根据每行的calendar_year值,动态筛选出年份大于等于它的列并计算乘积,新增年份列时无需修改代码。
实现代码
import polars as pl # 示例数据 df = pl.from_repr(""" ┌─────┬───────────────┬───────┬───────┬───────┬───────┬───────┬─────────┐ │ id ┆ calendar_year ┆ 2017 ┆ 2018 ┆ 2019 ┆ 2020 ┆ 2021 ┆ product │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 │ ╞═════╪═══════════════╪═══════╪═══════╪═══════╪═══════╪═══════╪═════════╡ │ 123 ┆ 2018 ┆ 0.998 ┆ 0.997 ┆ 0.996 ┆ 0.995 ┆ 0.994 ┆ 0.9801 │ │ 456 ┆ 2019 ┆ 0.993 ┆ 0.992 ┆ 0.991 ┆ 0.99 ┆ 0.989 ┆ 0.9557 │ └─────┴───────────────┴───────┴───────┴───────┴───────┴───────┴─────────┘ """) # 自动提取所有年份列(列名为数字的列)并按年份排序 year_cols = sorted([col for col in df.columns if col.isdigit()], key=int) # 构建向量化乘积表达式:仅相乘年份>=calendar_year的列 product_expr = pl.fold( acc=pl.lit(1.0), function=lambda acc, col: acc * pl.when(pl.lit(int(col)) >= pl.col("calendar_year")).then(pl.col(col)).otherwise(pl.lit(1.0)), exprs=year_cols ).alias("product") # 计算并添加product列 result_df = df.with_columns(product_expr) print(result_df)
代码说明
- 自动识别年份列:通过判断列名是否为数字,自动捕获所有年份列,新增
2022、2023等列时无需修改代码。 - 向量化计算:使用
pl.fold实现高效的向量化累积乘积,比行级循环(如map_elements)性能更优,适合大数据集。 - 动态筛选逻辑:通过
pl.when判断当前列的年份是否大于等于calendar_year,满足条件则取列值参与乘积,否则取1(不影响乘积结果)。
运行结果
输出的DataFrame会包含正确计算的product列,与示例中的预期值一致:
┌─────┬───────────────┬───────┬───────┬───────┬───────┬───────┬──────────┐ │ id ┆ calendar_year ┆ 2017 ┆ 2018 ┆ 2019 ┆ 2020 ┆ 2021 ┆ product │ │ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 ┆ f64 │ ╞═════╪═══════════════╪═══════╪═══════╪═══════╪═══════╪═══════╪══════════╡ │ 123 ┆ 2018 ┆ 0.998 ┆ 0.997 ┆ 0.996 ┆ 0.995 ┆ 0.994 ┆ 0.98010… │ │ 456 ┆ 2019 ┆ 0.993 ┆ 0.992 ┆ 0.991 ┆ 0.99 ┆ 0.989 ┆ 0.95571… │ └─────┴───────────────┴───────┴───────┴───────┴───────┴───────┴──────────┘
内容的提问来源于stack exchange,提问作者Max Herring
相关产品推荐
相关产品推荐

