在与polars数据框链式表达式时,with_columns_seq操作出现ComputeError

3 投票
1 回答
54 浏览
提问于 2025-04-14 17:31

我正在尝试对一个懒加载的polars数据框中的单列进行一系列操作,但我想避免重复使用with_columns_seq。然而,我遇到了一个ComputeError,提示有重复的列名。有没有更好的方法可以解决这个问题呢?

df = (
    df
        .with_columns_seq([
            pl.col('sentiment').cast(pl.UInt8),
            pl.col('review').map_elements(lambda x: BeautifulSoup(x).get_text()),
            pl.col('review').str.replace(r"[^a-zA-Z0-9]", " "),
            pl.col('review').str.to_lowercase(),
            # pl.col('review').str.split_by(' ')
        ])
    
)

df.collect().head()

而且错误信息是

ComputeError: the name: 'review' passed to `LazyFrame.with_columns` is duplicate

It's possible that multiple expressions are returning the same default column name. If this is the case, try renaming the columns with `.alias("new_name")` to avoid duplicate column names.

我试着把所有操作组合在一起,但因为重复的列名出错了。

1 个回答

4

解释

你的错误信息几乎已经告诉你问题的所有内容:

可能有多个表达式返回了相同的默认列名。如果是这种情况,尝试用 .alias("new_name") 来重命名列,以避免重复的列名。

不过,这里并没有给出你可能想要的解决方案。

错误的原因是每一行以 pl.col("review") 开头的代码都会创建一个新的 review 列,因为 .with_columns_seq 并不是说你一个接一个地运行这些表达式来更新数据。它只是意味着没有使用并行处理来完成这个操作,你完全可以使用 with_columns

通常的解决办法是使用 alias("new_name"),就像错误信息中提到的那样。但在你的情况下,这样做只会创建两个数据稍有不同的列。

        .with_columns_seq([
            pl.col('review').map_elements(lambda x: x),
            pl.col('review').str.to_lowercase().alias("lowercase"),
        ])
┌───────────┬──────────────────────┬──────────────────────┐
│ sentiment ┆ review               ┆ lowercase            │
│ ---       ┆ ---                  ┆ ---                  │
│ i64       ┆ str                  ┆ str                  │
╞═══════════╪══════════════════════╪══════════════════════╡
│ 1         ┆ I love this movie    ┆ i love this movie    │
│ 0         ┆ I hate this movie!!  ┆ i hate this movie!!  │
...

这似乎不是你想要的。相反,你需要一种方法来顺序地对新的 review 列执行每一个操作。

解决方案

要顺序地运行这些针对 review 的表达式,你需要 将它们连接起来

表达式的强大之处在于每个表达式都会产生一个新的表达式,并且它们可以连接在一起。你可以通过将表达式传递给 Polars 的执行上下文来运行它们。

所以你应该这样做:

df = (
    df
        .with_columns([
            pl.col('sentiment').cast(pl.UInt8),
            pl.col('review').map_elements(lambda x: BeautifulSoup(x).get_text())
                .str.replace_all(r"[^a-zA-Z0-9]", " ")
                .str.to_lowercase()
        ])
    
)

撰写回答