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

基于多条件与通配符的Polars DataFrame列值查找优化方案

问题描述

我有如下Polars DataFrame:

df = pl.DataFrame({'Col1': ['a', 'a', 'a', 'b', 'b', 'b', 'b', 'aa', 'aa', 'aa']
                   , 'Col2': ['c', 'd', 'e', 'c', 'd', 'e', 'f', 'd', 'e', 'f']
                   , 'Col3': ['i', 'i', 'j', 'T', 'j', 'k', 'l', 'j', 'k', 'l']
                   , 'Col4': ['m', 'n', 'o', 'p', 'r', 's', 'z', 'r', 's', 'z']})

数据结构如下:

shape: (10, 4)
┌──────┬──────┬──────┬──────┐
│ Col1 ┆ Col2 ┆ Col3 ┆ Col4 │
│ ---  ┆ ---  ┆ ---  ┆ ---  │
│ str  ┆ str  ┆ str  ┆ str  │
╞══════╪══════╪══════╪══════╡
│ a    ┆ c    ┆ i    ┆ m    │
│ a    ┆ d    ┆ i    ┆ n    │
│ a    ┆ e    ┆ j    ┆ o    │
│ b    ┆ c    ┆ T    ┆ p    │
│ …    ┆ …    ┆ …    ┆ …    │
│ b    ┆ f    ┆ l    ┆ z    │
│ aa   ┆ d    ┆ j    ┆ r    │
│ aa   ┆ e    ┆ k    ┆ s    │
│ aa   ┆ f    ┆ l    ┆ z    │
└──────┴──────┴──────┴──────┘

同时有一套按优先级排序的输出匹配规则(最后一条为默认规则):

┌──────┬──────┬──────┬──────┬────────┐
│ Col1 ┆ Col2 ┆ Col3 ┆ Col4 ┆ Output │
╞══════╪══════╪══════╪══════╪════════╡
│ a    ┆ *    ┆ *    ┆ n    ┆ out2   │
│ a    ┆ *    ┆ *    ┆ *    ┆ out1   │
│ b    ┆ *    ┆ <>T  ┆ *    ┆ out2   │
│ aa   ┆ d    ┆ *    ┆ *    ┆ out3   │
│ aa   ┆ e    ┆ *    ┆ *    ┆ out4   │
│ aa   ┆ f    ┆ *    ┆ *    ┆ out5   │
│ *    ┆ *    ┆ *    ┆ *    ┆ Unknown│
└──────┴──────┴──────┴──────┴────────┘

期望输出结果:

shape: (10, 5)
┌──────┬──────┬──────┬──────┬─────────┐
│ Col1 ┆ Col2 ┆ Col3 ┆ Col4 ┆ Output  │
│ ---  ┆ ---  ┆ ---  ┆ ---  ┆ ---     │
│ str  ┆ str  ┆ str  ┆ str  ┆ str     │
╞══════╪══════╪══════╪══════╪═════════╡
│ a    ┆ c    ┆ i    ┆ m    ┆ out1    │
│ a    ┆ d    ┆ i    ┆ n    ┆ out2    │
│ a    ┆ e    ┆ j    ┆ o    ┆ out1    │
│ b    ┆ c    ┆ T    ┆ p    ┆ Unknown │
│ b    ┆ d    ┆ j    ┆ r    ┆ out2    │
│ b    ┆ e    ┆ k    ┆ s    ┆ out2    │
│ b    ┆ f    ┆ l    ┆ z    ┆ out2    │
│ aa   ┆ d    ┆ j    ┆ r    ┆ out3    │
│ aa   ┆ e    ┆ k    ┆ s    ┆ out4    │
│ aa   ┆ f    ┆ l    ┆ z    ┆ out5    │
└──────┴──────┴──────┴──────┴─────────┘

目前我可以用嵌套的pl.when(...).then(...).otherwise(...)实现,但规则数量增多时会非常繁琐。想知道有没有更优的实现方式,考虑过用join,但不确定如何处理通配符和规则优先级。


解决方案

方法一:结构化规则+动态构建条件链

把规则整理成结构化的条件列表,按优先级排序后循环生成when-then逻辑,避免手动嵌套,扩展性更好:

import polars as pl

df = pl.DataFrame({'Col1': ['a', 'a', 'a', 'b', 'b', 'b', 'b', 'aa', 'aa', 'aa']
                   , 'Col2': ['c', 'd', 'e', 'c', 'd', 'e', 'f', 'd', 'e', 'f']
                   , 'Col3': ['i', 'i', 'j', 'T', 'j', 'k', 'l', 'j', 'k', 'l']
                   , 'Col4': ['m', 'n', 'o', 'p', 'r', 's', 'z', 'r', 's', 'z']})

# 按优先级从高到低定义规则:(条件表达式, 对应输出值)
rules = [
    (pl.col("Col1") == "a") & (pl.col("Col4") == "n", "out2"),
    (pl.col("Col1") == "a", "out1"),
    (pl.col("Col1") == "b") & (pl.col("Col3") != "T", "out2"),
    (pl.col("Col1") == "aa") & (pl.col("Col2") == "d", "out3"),
    (pl.col("Col1") == "aa") & (pl.col("Col2") == "e", "out4"),
    (pl.col("Col1") == "aa") & (pl.col("Col2") == "f", "out5"),
]

# 初始化输出表达式,默认值为Unknown
output_expr = pl.lit("Unknown")

# 按规则优先级倒序构建条件链(高优先级规则覆盖低优先级)
for cond, val in reversed(rules):
    output_expr = pl.when(cond).then(val).otherwise(output_expr)

# 添加Output列到原始DataFrame
result_df = df.with_columns(Output=output_expr)
print(result_df)

当需要新增规则时,只需要在rules列表中添加对应的(条件, 值)对即可,无需修改嵌套逻辑。

方法二:规则DataFrame+笛卡尔积匹配+优先级过滤

如果规则数量极大或需要从外部加载(比如CSV/数据库),可以把规则转换成DataFrame,通过笛卡尔积匹配后筛选优先级最高的结果:

import polars as pl

df = pl.DataFrame({'Col1': ['a', 'a', 'a', 'b', 'b', 'b', 'b', 'aa', 'aa', 'aa']
                   , 'Col2': ['c', 'd', 'e', 'c', 'd', 'e', 'f', 'd', 'e', 'f']
                   , 'Col3': ['i', 'i', 'j', 'T', 'j', 'k', 'l', 'j', 'k', 'l']
                   , 'Col4': ['m', 'n', 'o', 'p', 'r', 's', 'z', 'r', 's', 'z']})

# 规则DataFrame,添加priority列标记优先级(数字越小优先级越高)
rules_df = pl.DataFrame({
    "Col1": ["a", "a", "b", "aa", "aa", "aa", "*"],
    "Col2": ["*", "*", "*", "d", "e", "f", "*"],
    "Col3": ["*", "*", "<>T", "*", "*", "*", "*"],
    "Col4": ["n", "*", "*", "*", "*", "*", "*"],
    "Output": ["out2", "out1", "out2", "out3", "out4", "out5", "Unknown"],
    "priority": [1, 2, 3, 4, 5, 6, 7]
})

# 笛卡尔积关联原始数据和规则
cross_df = df.join(rules_df, how="cross")

# 构建匹配条件:处理*通配符和<>X不等于规则
match_cond = pl.lit(True)
for col in ["Col1", "Col2", "Col3", "Col4"]:
    match_cond = match_cond & pl.when(
        pl.col(f"{col}_right") == "*"
    ).then(True).when(
        pl.col(f"{col}_right").str.starts_with("<>")
    ).then(pl.col(col) != pl.col(f"{col}_right").str.slice(2)).otherwise(
        pl.col(col) == pl.col(f"{col}_right")
    )

# 筛选匹配的规则行,按原始数据分组后取优先级最高的Output
result_df = cross_df.filter(match_cond).group_by(df.columns).agg(
    pl.col("Output").sort_by("priority").first()
)

# 按原始列排序恢复顺序
print(result_df.sort(df.columns))

这种方法完全通过规则DataFrame配置逻辑,无需修改代码,适合规则频繁变动或数量庞大的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 12:25:56