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

如何在Python(pandas)中实现类SQL子查询的条件关联?

Pandas实现无关联键的范围匹配获取category

数据示例

先定义示例DataFrame:

import pandas as pd

# df1示例数据
df1 = pd.DataFrame({
    'id': [1, 2, 3, 4],
    'code': [150, 250, 350, 450]
})

# df2示例数据,s_date仅包含20210101和20220101
df2 = pd.DataFrame({
    's_date': [20210101, 20210101, 20220101, 20220101],
    'range1': [100, 300, 100, 300],
    'range2': [200, 400, 200, 400],
    'category': ['A', 'B', 'C', 'D']
})

参考SQL代码(用户原实现)

假设你使用的SQL逻辑如下:

SELECT 
    df1.*,
    df2.category,
    df2.s_date
FROM df1
LEFT JOIN df2 
ON df1.code BETWEEN df2.range1 AND df2.range2
AND df2.s_date IN (20210101, 20220101);

Pandas实现方法

方法1:笛卡尔积合并后过滤(适合小数据量)

通过临时键实现交叉合并,再筛选符合范围和日期条件的行,最后关联回原df1保留所有行:

# 添加临时键实现笛卡尔积
cross_merged = pd.merge(df1.assign(temp_key=1), df2.assign(temp_key=1), on='temp_key').drop('temp_key', axis=1)

# 过滤符合条件的记录
filtered = cross_merged[
    cross_merged['code'].between(cross_merged['range1'], cross_merged['range2']) &
    cross_merged['s_date'].isin([20210101, 20220101])
]

# 关联回df1,保留原表所有行
final_result = df1.merge(filtered[['id', 's_date', 'category']], on='id', how='left')

方法2:逐行匹配(灵活但大数据量效率低)

使用apply逐行对df1的code匹配df2中的符合条件记录:

def match_category(row):
    # 筛选df2中满足范围和日期条件的行
    matched_rows = df2[
        (df2['range1'] <= row['code']) &
        (row['code'] <= df2['range2']) &
        (df2['s_date'].isin([20210101, 20220101]))
    ]
    # 返回所有匹配的category(用逗号分隔,可根据需求调整为列表或取第一个)
    return ','.join(matched_rows['category']) if not matched_rows.empty else None

# 新增category列
df1['category'] = df1.apply(match_category, axis=1)
# 如果需要保留s_date,可修改函数返回元组后拆分列

方法3:merge_asof高效匹配(适合有序范围)

如果df2的range1是有序的,使用merge_asof可以大幅提升效率:

# 对df1按code排序,df2按range1排序并过滤日期
df1_sorted = df1.sort_values('code').reset_index(drop=True)
df2_filtered_sorted = df2[
    df2['s_date'].isin([20210101, 20220101])
].sort_values('range1').reset_index(drop=True)

# 用merge_asof匹配code >= range1的最近记录
merged = pd.merge_asof(
    df1_sorted,
    df2_filtered_sorted,
    left_on='code',
    right_on='range1',
    direction='backward'
)

# 再过滤code <= range2的记录
result = merged[merged['code'] <= merged['range2']]

# 关联回原df1保留所有行
final_result = df1.merge(result[['id', 's_date', 'category']], on='id', how='left')

方法选择建议

  • 小数据集:方法1或方法2,实现简单直观
  • 大数据集:优先方法3,merge_asof是基于排序的高效匹配,性能远优于前两种

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 02:31:16