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

如何在Polars中执行仅向后匹配特定条件的join_asof操作

在Polars中实现匹配历史行的需求

完全可以实现你的需求,而且用窗口函数比join_asof更简洁高效,以下是两种可行方案:

方案一:窗口函数(推荐)

通过分组窗口的shift操作直接获取同组内的最近历史值,无需额外连接操作:

import polars as pl

pl.Config(tbl_rows=15)

df = pl.from_repr("""
┌────────┬─────┬───────┬───────┬───────────────┐
│ Season ┆ Wk  ┆ Team  ┆ Field ┆ GeneralLambda │
│ ---    ┆ --- ┆ ---   ┆ ---   ┆ ---           │
│ i64    ┆ i64 ┆ str   ┆ str   ┆ f64           │
╞════════╪═════╪═══════╪═══════╪═══════════════╡
│ 2024   ┆ 25  ┆ TeamA ┆ Away  ┆ 2.123456      │
│ 2024   ┆ 25  ┆ TeamB ┆ Home  ┆ 1.234567      │
│ 2024   ┆ 25  ┆ TeamC ┆ Away  ┆ 0.987654      │
│ 2024   ┆ 25  ┆ TeamD ┆ Home  ┆ 1.345678      │
│ 2024   ┆ 25  ┆ TeamE ┆ Away  ┆ 1.456789      │
│ 2024   ┆ 26  ┆ TeamA ┆ Home  ┆ 1.234567      │
│ 2024   ┆ 26  ┆ TeamB ┆ Away  ┆ 1.345678      │
│ 2024   ┆ 26  ┆ TeamC ┆ Home  ┆ 0.876543      │
│ 2024   ┆ 26  ┆ TeamD ┆ Away  ┆ 1.456789      │
│ 2024   ┆ 26  ┆ TeamE ┆ Home  ┆ 1.56789       │
│ 2024   ┆ 27  ┆ TeamA ┆ Away  ┆ 2.278759      │
│ 2024   ┆ 27  ┆ TeamB ┆ Away  ┆ 1.103829      │
│ 2024   ┆ 27  ┆ TeamC ┆ Home  ┆ 0.992563      │
│ 2024   ┆ 27  ┆ TeamD ┆ Home  ┆ 1.089324      │
│ 2024   ┆ 27  ┆ TeamE ┆ Home  ┆ 1.074221      │
└────────┴─────┴───────┴───────┴───────────────┘
""")

result = df.with_columns(
    pl.col("GeneralLambda")
    .shift(1)  # 取同组内上一行的历史值
    .over(["Team", "Field"])  # 按球队和主客场分组
    .sort_by("Wk")  # 分组内按周数排序,保证历史顺序正确
    .fill_null(
        # 对无历史记录的行填充自定义格式字符串
        pl.col("Team").str.extract(r"Team(.*)", 1) + "Last" + pl.col("Field") + "Value"
    )
    .alias("Prev_GeneralLambda")
)

print(result)

代码说明:

  • over(["Team", "Field"]):限定仅在相同球队+相同主客场的组内查找历史记录
  • .shift(1):获取组内上一行的GeneralLambda,由于提前按Wk排序,上一行就是周数更小的最近记录
  • .fill_null(...):对没有历史记录的行(如Wk=25的所有行),自动拼接成你需要的格式字符串

方案二:使用join_asof

如果坚持要用join_asof,可以按以下方式实现:

# 先对原表按分组键和周数排序
sorted_df = df.sort(["Team", "Field", "Wk"])

# 执行asof连接,匹配相同Team+Field且Wk更小的最近行
result = sorted_df.join_asof(
    sorted_df,
    by=["Team", "Field"],  # 完全匹配的列
    on="Wk",  # 按周数进行范围匹配
    strategy="backward",  # 查找小于当前Wk的最大匹配值
    suffix="_prev"
).with_columns(
    # 填充空值并整理列名
    pl.col("GeneralLambda_prev")
    .fill_null(
        pl.col("Team").str.extract(r"Team(.*)", 1) + "Last" + pl.col("Field") + "Value"
    )
    .alias("Prev_GeneralLambda")
).drop(["Season_prev", "Wk_prev", "GeneralLambda_prev"])  # 移除多余的连接列

print(result)

代码说明:

  • strategy="backward":确保仅匹配Wk小于当前行的最近记录
  • by=["Team", "Field"]:保证只有球队和主客场完全匹配的行才会被连接
  • 最后需要手动移除连接产生的重复列,相比窗口函数步骤更繁琐

两种方案都会生成你期望的结果,其中窗口函数方案性能更优,代码更简洁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 16:09:53