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

Pandas按日期精确/字符串部分匹配合并DataFrame及后处理方法

跨酒店房型匹配问题

需求描述

现有跨酒店房型匹配业务场景:具备可比性的同类房型可能存在不同名称变体。其中df1存储指定酒店(酒店X)的数据,df2存储其竞争对手(酒店A、酒店B)的数据,匹配规则为:同日期下,竞品房型名以酒店X房型名为前缀即判定为匹配,同一房型匹配到多个竞品房型时,取名称最短的匹配项。
逐行处理的方案在数据规模增长时扩展性差,现提供示例数据集,需要用高效的方式得到预期输出。
房型匹配规则参考

示例数据集构造代码

import pandas as pd
df1 = pd.DataFrame({"date": ["2022-06-15", "2022-06-15", "2022-06-15", "2022-06-26", "2022-06-26"],
                    "type": ["superior", "premier", "grand", "suite", "suite"]})
df2 = pd.DataFrame({"date": ["2022-06-15", "2022-06-15", "2022-06-15", "2022-06-15", "2022-06-15", "2022-06-15", "2022-06-15", "2022-06-26", "2022-06-26", "2022-06-26", "2022-06-26"],
                    "competitor": ["A", "A", "A", "A", "B", "B", "B", "A", "A", "B", "B"],
                    "type": ["superior studio", "superior double studio", "premier studio", "premier double room", "superior", "superior double", "grand suite", "superior studio", "premier studio", "grand suite", "superior"],
                    "value": [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110]})

已尝试方案

目前已通过pandasql实现部分匹配逻辑,但不清楚如何用纯pandas完成后续处理得到最终结果,已实现代码如下:

from pandasql import sqldf
df_A = df2[df2["competitor"] == "A"].reset_index(drop=True)
df_B = df2[df2["competitor"] == "B"].reset_index(drop=True)

sql = """SELECT
            df1.date,
            df1.type,
            df_A.type as A,
            df_A.value as val_A,
            df_B.type as B,
            df_B.value as val_B
        FROM df1
        LEFT JOIN df_A
        ON df_A.type LIKE df1.type || '%' AND df1.date = df_A.date
        LEFT JOIN df_B
        ON df_B.type LIKE df1.type || '%' AND df1.date = df_B.date"""

temp = sqldf(sql, locals())

纯Pandas高效实现方案

采用向量化操作替代逐行遍历,数据量增长时性能表现稳定,实现逻辑如下:

  • 先通过merge做日期维度的关联,避免全量笛卡尔积
  • 用字符串前缀匹配规则过滤符合要求的房型对
  • 按房型名称长度排序,同匹配组取长度最短的结果作为最优匹配
  • 透视转换为要求的宽表格式,补全未匹配到的行
# 1. 按日期关联两张表,缩小匹配范围
merged = df1.merge(df2, on="date", how="left", suffixes=("", "_comp"))

# 2. 过滤前缀匹配的房型
merged = merged[merged.apply(lambda x: x["type_comp"].startswith(x["type"]), axis=1)]

# 3. 按匹配优先级排序:名称越短匹配度越高,同组保留最优匹配
merged["name_len"] = merged["type_comp"].str.len()
merged = (merged.sort_values(["date", "type", "competitor", "name_len"])
          .drop_duplicates(["date", "type", "competitor"], keep="first"))

# 4. 长表转宽表,调整列格式
pivot = merged.pivot(index=["date", "type"], columns="competitor", values=["type_comp", "value"])
pivot.columns = [c[1] if c[0] == "type_comp" else f"val_{c[1]}" for c in pivot.columns]
pivot = pivot[["A", "val_A", "B", "val_B"]].reset_index()

# 5. 补全df1中无匹配结果的行
final_result = df1.merge(pivot, on=["date", "type"], how="left")

运行后得到的结果与预期完全一致:

  • 2022-06-15的superior房型匹配到A的superior studio(val_A=10)、B的superior(val_B=50)
  • 2022-06-15的premier房型匹配到A的premier studio(val_A=30),B无匹配
  • 2022-06-15的grand房型匹配到B的grand suite(val_B=70),A无匹配
  • 2022-06-26的suite房型匹配到B的grand suite(val_B=100),A无匹配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 23:36:21