Pandas新手求助:如何实现基于子串匹配的左连接?
嘿,作为Pandas新手碰到这种子串匹配+左连接的需求太正常了!我给你整理了几种不同场景下的实现方法,你可以根据自己的数据集大小和格式来选~
先准备示例数据
先创建两个测试用的DataFrame,方便你跟着代码实操:
import pandas as pd # 左表:需要保留所有行的DataFrame df1 = pd.DataFrame({ 'parcel': ['ABC123', 'DEF456', 'GHI789', 'JKL012'], 'value1': [10, 20, 30, 40] }) # 右表:用来匹配子串的DataFrame df2 = pd.DataFrame({ 'parcel_id': ['X-ABC123-Y', 'Z-DEF456-W', 'M-NOP345-Q'], 'value2': [100, 200, 300] })
方法1:逐行匹配(适合小数据集)
如果你的数据量不大,用apply逐行处理最直观,逻辑也容易理解:
# 定义一个函数,根据parcel值查找匹配的value2 def get_matching_value(parcel_str): # 筛选右表中parcel_id包含当前parcel的行 matched_rows = df2[df2['parcel_id'].str.contains(parcel_str)] # 有匹配返回第一个结果,无匹配返回空值 return matched_rows['value2'].iloc[0] if not matched_rows.empty else pd.NA # 给左表添加匹配到的列 df1['value2'] = df1['parcel'].apply(get_matching_value) print(df1)
运行后会得到你要的左连接结果:
| parcel | value1 | value2 |
|---|---|---|
| ABC123 | 10 | 100 |
| DEF456 | 20 | 200 |
| GHI789 | 30 | |
| JKL012 | 40 |
方法2:交叉连接+过滤(适合中等数据集)
如果数据量稍大,逐行apply会比较慢,用交叉连接+向量化过滤的效率更高:
# 给两个表加临时key,用于做交叉连接 df1['temp_key'] = 1 df2['temp_key'] = 1 # 生成所有可能的组合 cross_df = pd.merge(df1, df2, on='temp_key') # 筛选出parcel_id包含对应parcel的行 matched_df = cross_df[cross_df['parcel_id'].str.contains(cross_df['parcel'])] # 左连接回原左表,保留所有行 result_df = df1.merge( matched_df[['parcel', 'parcel_id', 'value2']], on='parcel', how='left' ).drop('temp_key', axis=1) print(result_df)
方法3:提取固定格式子串(效率最高,适合有规律的场景)
如果你的parcel在parcel_id里是固定格式的片段(比如都是被-包裹的中间部分),直接提取后做等值连接是最快的:
# 从parcel_id中提取出和parcel匹配的部分(这里假设格式是X-XXX-Y) df2['parcel'] = df2['parcel_id'].str.extract(r'-(.*)-') # 直接做左连接,完美匹配 result_df = df1.merge(df2[['parcel', 'parcel_id', 'value2']], on='parcel', how='left') print(result_df)
额外注意事项
- 子串匹配默认区分大小写,如果需要忽略大小写,在
str.contains里加case=False参数即可,比如df2['parcel_id'].str.contains(parcel_str, case=False) - 如果右表中有多个匹配项,上面的方法会返回第一个匹配结果,你可以根据需求修改逻辑(比如返回所有匹配值的列表、最大值等)
内容的提问来源于stack exchange,提问作者NoSoyTuMadre
相关产品推荐
相关产品推荐

