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

如何无需预处理合并汽车DataFrame?求精准匹配方案及代码

问题描述

我有两个DataFrame:

df1

model_detail                                        series_detail
Nissan Sentra 430 Sedan -1123                            Nissan Sentra 
Acura ILX150 Base Sedan -17652                          Acura ILX Sedan
Acura TLX300 Base FWD -89789                            Acura TLX Sedan
Acura MDX450 Advanced Electric Hybrid AWD -55647        Acura MDX Sedan

df_2

Name           model                      Series      Amount         
  Acura       MDX 450 Hybrid                 MDX        45900
  Acura       ILX 150 Sedan                  ILX        156700
  Nissan      Sentra 430 Electric           Sentra      88897
  Nissan      Sunny 150                     Sunny       12333
  Acura       MDX 450 Electric               MDX        90000

需要将df1与df2合并,把Amount列加入df1中。涉及40个汽车品牌且格式各异,统一转换格式工作量极大。目前的处理方法是手动提取并校验,效率低且易出错:

def model_extractfunc(row):
    blocks = row['model_detail'].split()
    mid_index = 1
    if ('Hybrid' in blocks) or ('Electric' in blocks) or('Connect' in blocks):
        mid_index = 3
    return ' '.join(blocks[1:mid_index+1])

df1['extract_model'] = df1.apply(model_extractfunc, axis=1)

想知道有没有其他合并方式?模糊匹配是否可行?或者替代方案?要求保证Amount列匹配的准确性,同时提供代码示例。

可行解决方案

1. 优化规则提取,减少手动干预

针对车型编号、关键词的规律,用正则表达式提取核心信息,匹配df2的字段:

代码示例

import pandas as pd
import re

# 处理df1:提取品牌、系列、车型编号、动力类型
def parse_df1(row):
    # 提取品牌(第一个单词)
    brand = row['model_detail'].split()[0]
    # 提取系列(匹配常见系列关键词,可扩展)
    series_match = re.search(r'(Sentra|ILX|TLX|MDX)', row['model_detail'])
    series = series_match.group() if series_match else None
    # 提取车型编号(3位数字)
    num_match = re.search(r'(\d{3})', row['model_detail'])
    model_num = num_match.group() if num_match else None
    # 提取动力类型
    power_type = None
    if 'Hybrid' in row['model_detail']:
        power_type = 'Hybrid'
    elif 'Electric' in row['model_detail']:
        power_type = 'Electric'
    return pd.Series([brand, series, model_num, power_type], 
                     index=['brand', 'series', 'model_num', 'power_type'])

df1_parsed = df1.join(df1.apply(parse_df1, axis=1))

# 处理df2:拆分model字段提取编号和动力类型
def parse_df2(row):
    # 提取车型编号
    num_match = re.search(r'(\d{3})', row['model'])
    model_num = num_match.group() if num_match else None
    # 提取动力类型
    power_type = None
    if 'Hybrid' in row['model']:
        power_type = 'Hybrid'
    elif 'Electric' in row['model']:
        power_type = 'Electric'
    return pd.Series([model_num, power_type], 
                     index=['model_num', 'power_type'])

df2_parsed = df2.join(df2.apply(parse_df2, axis=1))

# 优先按品牌+系列+编号+动力类型合并
merged = pd.merge(df1_parsed, df2_parsed, 
                  left_on=['brand', 'series', 'model_num', 'power_type'],
                  right_on=['Name', 'Series', 'model_num', 'power_type'],
                  how='left')

# 处理动力类型不匹配但核心字段匹配的情况
merged_backup = pd.merge(df1_parsed, df2_parsed,
                         left_on=['brand', 'series', 'model_num'],
                         right_on=['Name', 'Series', 'model_num'],
                         how='left', suffixes=('', '_backup'))

# 填充未匹配到的Amount
merged['Amount'] = merged['Amount'].fillna(merged_backup['Amount_backup'])
merged = merged.drop(columns=['Name', 'Series', 'model_num_backup', 'power_type_backup', 'model_backup'])

2. 模糊匹配+人工校验(保证准确性)

用fuzzywuzzy库计算字符串相似度,设定阈值筛选匹配结果,仅对少量存疑项人工复核:

代码示例

from fuzzywuzzy import process, fuzz
import pandas as pd

# 为df2创建组合匹配键
df2['match_key'] = df2['Name'] + ' ' + df2['model'] + ' ' + df2['Series']

# 为df1创建组合匹配键
df1['match_key'] = df1['model_detail'] + ' ' + df1['series_detail']

# 定义模糊匹配函数,设定相似度阈值(比如80)
def fuzzy_match(row):
    match, score = process.extractOne(row['match_key'], df2['match_key'], scorer=fuzz.token_set_ratio)
    if score >= 80:
        return df2[df2['match_key'] == match]['Amount'].values[0]
    else:
        return None

df1['Amount'] = df1.apply(fuzzy_match, axis=1)

# 导出未匹配的行进行人工复核
unmatched = df1[df1['Amount'].isna()]
unmatched.to_csv('unmatched_cars.csv', index=False)

注意:使用前需安装依赖:pip install fuzzywuzzy python-Levenshtein

3. 建立品牌-系列映射字典

针对40个品牌,预先整理系列映射关系,再结合规则过滤车型细节:

代码示例

import pandas as pd
import re

# 预先整理品牌-系列映射(可根据实际品牌扩展)
brand_series_map = {
    'Nissan': ['Sentra', 'Sunny'],
    'Acura': ['ILX', 'TLX', 'MDX']
}

# 提取df1的品牌和系列
df1['brand'] = df1['model_detail'].str.split().str[0]
df1['series'] = df1['series_detail'].str.split().str[1]

# 提取df2的品牌和系列
df2['brand'] = df2['Name']
df2['series'] = df2['Series']

# 先按品牌+系列合并
merged = pd.merge(df1, df2, on=['brand', 'series'], how='left')

# 针对同系列多车型,过滤匹配编号和动力类型
def filter_amount(row):
    if pd.isna(row['Amount']):
        return None
    # 提取编号
    df1_num = re.search(r'(\d{3})', row['model_detail']).group() if re.search(r'(\d{3})', row['model_detail']) else ''
    df2_num = re.search(r'(\d{3})', row['model']).group() if re.search(r'(\d{3})', row['model']) else ''
    # 提取动力类型
    df1_power = 'Hybrid' if 'Hybrid' in row['model_detail'] else 'Electric' if 'Electric' in row['model_detail'] else ''
    df2_power = 'Hybrid' if 'Hybrid' in row['model'] else 'Electric' if 'Electric' in row['model'] else ''
    # 校验匹配
    if df1_num == df2_num and (df1_power == df2_power or df1_power == ''):
        return row['Amount']
    else:
        return None

merged['Amount'] = merged.apply(filter_amount, axis=1)
# 合并重复行,保留有效Amount
merged = merged.groupby(df1.columns.tolist())['Amount'].first().reset_index()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 17:45:38