Python-极性:如何将列表中的每个元素与不同列中的值相乘?

问题描述 投票:0回答:3

我有一个具有一定数量组的数据框,包含一个权重列和一个值列表,可以是任意长度,例如:

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]]
    }
)
┌────────┬────────┬─────────────────┐
│ 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]      │
└────────┴────────┴─────────────────┘

我的目标是计算一个“加权”列,它是值列表中每个项目与权重列中的值的倍数:

┌────────┬────────┬─────────────────┬─────────────────┐
│ 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").arr.eval(pl.element() * 3).alias("Weight1"), #Multiplying with literal works
        pl.col("Vals").arr.eval(pl.element() * pl.col("Weight")).alias("Weight2"), #Does not work
        pl.col("Vals").arr.eval(pl.element() * pl.col("Unknown")).alias("Weight3"), #Unknown columns give same value
        pl.col("Vals").arr.eval(pl.col("Vals") * pl.col("Weight")).alias("Weight4"), #Same effect
        # pl.col('Vals') * 3 -> gives an error
]
)
┌────────┬────────┬────────────┬────────────┬──────────────┬──────────────┬────────────────────┐
│ 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]       │
└────────┴────────┴────────────┴────────────┴──────────────┴──────────────┴────────────────────┘

除非我没有正确理解它,否则您似乎无法从 eval 函数内访问列表之外的列。也许有一种方法可以在语句中使用列表理解,但这看起来并不是一个很好的解决方案。

这里推荐的方法是什么?任何帮助将不胜感激!

python-polars
3个回答
2
投票

编辑 - 极地更新:

从最新版本的 Polars 开始,这是现在正确的语法:

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]]
    }
)

(df
    .explode('Vals')
    .with_columns(Weighted = pl.col('Weight')*pl.col('Vals'))
    .groupby('Group')
    .agg(
        pl.col('Weight').first(),                                                                                                             
        pl.col('Vals'),
        pl.col('Weighted')
        )                                                                                                 
)

旧答案:

(df
    .explode('Vals')
    .with_columns(Weighted = pl.col('Weight')*pl.col('Vals'))
    .groupby('Group')
    .agg([
        pl.col('Weight').first(),                                                                                                             
        pl.col('Vals').list(),
        pl.col('Weighted').list()
        ])                                                                                                 
)

1
投票

所以你可以通过两种方式解决这个问题。说实话我不知道哪一个更好,我还没有测试过性能或 RAM 使用情况。

算法1

我们可以将两列放入一个结构体中,然后对它们应用自定义函数。 (文档中对此进行了解释此处

import polars as pl
import numpy as np

def weighted_list(ls, weight):
    return(list(np.array(ls) * weight))

(df.with_columns([pl.struct(["Weight", "Vals"])
                  .apply(lambda x: weighted_list(x["Vals"], x["Weight"]))])
)

算法2

因此在这种情况下,您必须小心您的“Group”、“Weight”列是唯一的。因此,如果您有两个条目,例如 Group3 和 Weight 300。

(df.explode("Vals")
    .with_column((pl.col("Vals") * pl.col("Weight")).alias("Weighted"))
    .groupby(["Group", "Weight"])
    .agg([pl.list("Vals"), pl.list("Weighted")])
)

0
投票

不幸的是,尚不支持列表上的操作,但您可以使用 Struct 来解决它并避免数据爆炸和内爆。您可以从列

a
创建一个列表,然后通过将结构相乘并将其转换回列表来获得结果。

(
    df
    .with_columns(Weighted = pl.col.Weight.repeat_by(pl.col.Vals.list.len()))
    .with_columns(pl.col.Weighted.list.to_struct() * pl.col.Vals.list.to_struct())
    .with_columns(Weighted = pl.concat_list(pl.col.Weighted.struct.field("*")))
    .with_columns(pl.col.Weighted.list.drop_nulls().cast(pl.List(pl.Int64)))
)
┌────────┬────────┬─────────────────┬─────────────────┐
│ 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]      │
└────────┴────────┴─────────────────┴─────────────────┘
© www.soinside.com 2019 - 2024. All rights reserved.