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

如何用Polars将列表列元素与另一列数值逐一相乘?

问题描述

我有一个Polars DataFrame,包含分组列、Weight列和长度可变的Vals列表列,示例如下:

df = pl.DataFrame(
    {
        "Group": ["Group1", "Group2", "Group3"],
        "Weight": [100.0, 200.0, 300.0],
        "Vals": [[0.5, 0.5, 0.8],[0.5, 0.5, 0.8], [0.7, 0.9]]
    }
)

对应的DataFrame结构:

┌────────┬────────┬─────────────────┐
│ Group  ┆ Weight ┆ Vals            │
│ ---    ┆ ---    ┆ ---             │
│ str    ┆ f64    ┆ list[f64]       │
╞════════╪════════╪═════════════════╡
│ Group1 ┆ 100.0  ┆ [0.5, 0.5, 0.8] │
│ Group2 ┆ 200.0  ┆ [0.5, 0.5, 0.8] │
│ Group3 ┆ 300.0  ┆ [0.7, 0.9]      │
└────────┴────────┴─────────────────┘

目标是生成一个Weighted列,其中每个元素是Vals列表中对应元素与该行Weight值的乘积,预期结果如下:

┌────────┬────────┬─────────────────┬─────────────────┐
│ Group  ┆ Weight ┆ Vals            ┆ Weighted        │
│ ---    ┆ ---    ┆ ---             ┆ ---             │
│ str    ┆ f64    ┆ list[f64]       ┆ list[i64]       │
╞════════╪════════╪═════════════════╪═════════════════╡
│ Group1 ┆ 100.0  ┆ [0.5, 0.5, 0.8] ┆ [50, 50, 80]    │
│ Group2 ┆ 200.0  ┆ [0.5, 0.5, 0.8] ┆ [100, 100, 160] │
│ Group3 ┆ 300.0  ┆ [0.7, 0.9]      ┆ [210, 270]      │
└────────┴────────┴─────────────────┴─────────────────┘

尝试了几种方法,结果不符合预期:

df.with_columns(
    pl.col("Vals").list.eval(pl.element() * 3).alias("Weight1"), # 与字面量相乘有效
    pl.col("Vals").list.eval(pl.element() * pl.col("Weight")).alias("Weight2"), # 无效
    pl.col("Vals").list.eval(pl.element() * pl.col("Unknown")).alias("Weight3"), # 未知列得到相同错误结果
    pl.col("Vals").list.eval(pl.col("Vals") * pl.col("Weight")).alias("Weight4"), # 同样无效
    # pl.col('Vals') * 3 -> 报错
)

得到的错误结果:

┌────────┬────────┬────────────┬────────────┬──────────────┬──────────────┬────────────────────┐
│ Group  ┆ Weight ┆ Vals       ┆ Weight1    ┆ Weight2      ┆ Weight3      ┆ Weight4            │
│ ---    ┆ ---    ┆ ---        ┆ ---        ┆ ---          ┆ ---          ┆ ---                │
│ str    ┆ f64    ┆ list[f64]  ┆ list[f64]  ┆ list[f64]    ┆ list[f64]    ┆ list[f64]          │
╞════════╪════════╪════════════╪════════════╪══════════════╪══════════════╪════════════════════╡
│ Group1 ┆ 100.0  ┆ [0.5, 0.5, ┆ [1.5, 1.5, ┆ [0.25, 0.25, ┆ [0.25, 0.25, ┆ [0.25, 0.25, 0.64] │
│        ┆        ┆ 0.8]       ┆ 2.4]       ┆ 0.64]        ┆ 0.64]        ┆                    │
│ Group2 ┆ 200.0  ┆ [0.5, 0.5, ┆ [1.5, 1.5, ┆ [0.25, 0.25, ┆ [0.25, 0.25, ┆ [0.25, 0.25, 0.64] │
│        ┆        ┆ 0.8]       ┆ 2.4]       ┆ 0.64]        ┆ 0.64]        ┆                    │
│ Group3 ┆ 300.0  ┆ [0.7, 0.9] ┆ [2.1, 2.7] ┆ [0.49, 0.81] ┆ [0.49, 0.81] ┆ [0.49, 0.81]       │
└────────┴────────┴────────────┴────────────┴──────────────┴──────────────┴────────────────────┘

问题在于list.eval函数中无法直接访问列表列之外的其他列,请问推荐的实现方法是什么?

解决方案

方法1:list.eval结合first()获取外部列

在list.eval的上下文里,外部列可以通过pl.col("Weight").first()获取当前行的标量值,因为每行的Weight是单一值,first()能正确拿到对应行的Weight:

df.with_columns(
    pl.col("Vals")
    .list.eval(pl.element() * pl.col("Weight").first())
    .cast(pl.List(pl.Int64))
    .alias("Weighted")
)

方法2:使用struct+map_elements

将Vals和Weight打包成结构体,再通过lambda遍历列表元素计算乘积:

df.with_columns(
    pl.struct(["Vals", "Weight"])
    .map_elements(lambda x: [v * x["Weight"] for v in x["Vals"]], return_dtype=pl.List(pl.Int64))
    .alias("Weighted")
)

方法3:展开后计算再聚合

适合复杂场景,先将列表展开为多行,计算乘积后再重新分组聚合回列表:

df.explode("Vals")
.with_columns((pl.col("Vals") * pl.col("Weight")).cast(pl.Int64).alias("Weighted"))
.group_by("Group", "Weight")
.agg(pl.col("Weighted").alias("Weighted"))

方法4:Polars 0.19+ 版本的pl.parent()

如果使用Polars 0.19及以上版本,可以直接用pl.parent()访问外部列,写法更直观:

df.with_columns(
    pl.col("Vals")
    .list.eval(pl.element() * pl.parent().col("Weight"))
    .cast(pl.List(pl.Int64))
    .alias("Weighted")
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:10:17