有没有更好的方法来仅返回 Polars 数组中的每个
pl.element()
(如果它与列表中包含的项目匹配)?
虽然它有效,但我收到错误
The predicate 'col("").is_in([Series])' in 'when->then->otherwise' is not a valid aggregation and might produce a different number of rows than the group_by operation would. This behavior is experimental and may be subject to change
警告,这让我相信可能有更简洁/更好的方法:
import polars as pl
terms = ['a', 'z']
(pl.LazyFrame({'a':['x y z']})
.select(pl.col('a')
.str.split(' ')
.list.eval(pl.when(pl.element().is_in(terms))
.then(pl.element())
.otherwise(None))
.list.drop_nulls()
.list.join(' ')
)
.fetch()
)
为了子孙后代,它用
.map_elements()
代替了我之前的尝试:
import polars as pl
import re
terms = ['a', 'z']
(pl.LazyFrame({'a':['x y z']})
.select(pl.col('a')
.str.split(' ')
.map_elements(lambda x: ' '.join(list(set(re.findall('|'.join(terms), x)))),
return_dtype = pl.Utf8)
)
.fetch()
)
除了 @jqurious 在评论中列出的技巧之外,您还可以进行正则表达式提取。这开始很简单,但当我尝试不同的东西时变得有点笨拙。 Rust 正则表达式引擎的优点是它的性能非常好。坏处是它没有环顾四周,所以周围的工作使它看起来很笨重。
在没有环顾四周的情况下,为了确保我们没有从斑马中取出 z,我必须提取术语前后的空格。当然,第一个字母之前没有空格,最后一个字母之后也没有空格,所以这就是我在初始列之前和之后连接空格的原因。此外,为了确保它可以连续捕获两个字母,我必须将所有单空格替换为双空格,在提取步骤后将其替换回单空格。
terms = ['a', 'z', 'x']
termsre = "(" + "|".join([f" {x} " for x in terms]) + ")"
(pl.LazyFrame({'a':['x y z z zebra a', 'x y z', 'a b c']})
.with_columns(
b = (pl.lit(" ") + pl.col('a')
.str.replace_all(" ", " ") + pl.lit(" "))
.str.extract_all(termsre)
.list.join('')
.str.replace_all(" "," ")
.str.strip_chars()
)
.collect()
)
shape: (3, 2)
┌─────────────────┬─────────┐
│ a ┆ b │
│ --- ┆ --- │
│ str ┆ str │
╞═════════════════╪═════════╡
│ x y z z zebra a ┆ x z z a │
│ x y z ┆ x z │
│ a b c ┆ a │
└─────────────────┴─────────┘
旁注,
fetch
用于调试有限行数。您通常希望使用 collect