如何基于多条件从另一DataFrame中提取指定数值?
解决方案:基于多条件匹配提取DataFrame对应字段
先明确条件规则
从样本数据来看,CONSTRUCTION_TYPE_FAMILY和CONSTRUCTION_TYPE的条件分为三类:
- 正向匹配:用
OR连接多个值,满足任意一个即符合条件 - 反向排除:以
Not/NOT:开头,需排除列表内的所有值 - 模糊匹配:如
H3xx代表匹配以H3开头的任意字符串
步骤1:编写条件解析工具函数
先实现两个辅助函数,用来拆解复杂的条件字符串:
import re def parse_family_condition(condition_str): """解析CONSTRUCTION_TYPE_FAMILY条件,返回正向匹配列表、排除列表、模糊匹配正则""" # 清理多余引号和首尾空格 cleaned = re.sub(r'["\'“”‘’]', '', condition_str.strip()) include = [] exclude = [] fuzzy_patterns = [] if cleaned.startswith("NOT:"): # 处理排除规则 exclude_items = [item.strip() for item in cleaned[4:].split(',')] for item in exclude_items: if 'xx' in item: # 把xx替换为任意字符的正则 fuzzy_patterns.append(re.compile(f"^{item.replace('xx', '.*')}$", re.IGNORECASE)) else: exclude.append(item) else: # 处理OR连接的正向规则 include_items = [item.strip() for item in cleaned.split('OR')] for item in include_items: if 'xx' in item: fuzzy_patterns.append(re.compile(f"^{item.replace('xx', '.*')}$", re.IGNORECASE)) else: include.append(item) return include, exclude, fuzzy_patterns def parse_type_condition(condition_str): """解析CONSTRUCTION_TYPE条件,返回是否为排除规则、目标匹配字符串""" cleaned = condition_str.strip() is_exclude = False target = "" if cleaned.startswith("Not "): is_exclude = True target = re.sub(r'["\'“”‘’]', '', cleaned[4:].strip()) else: target = re.sub(r'["\'“”‘’]', '', cleaned) return is_exclude, target
步骤2:编写行匹配逻辑
针对DataFrame B的每一行,匹配DataFrame A中符合所有条件的记录:
import pandas as pd def match_equipment(b_row, df_a): # 1. 先匹配CONSTRUCTOR(默认精确匹配,需模糊匹配可改成str.contains) filtered_a = df_a[df_a['CONSTRUCTOR'] == b_row['CONSTRUCTOR']] if filtered_a.empty: return pd.Series([None, None]) # 2. 处理CONSTRUCTION_TYPE条件 type_is_exclude, type_target = parse_type_condition(b_row['CONSTRUCTION_TYPE']) if type_is_exclude: filtered_a = filtered_a[~filtered_a['CONSTRUCTION_TYPE'].str.contains(type_target, na=False)] else: filtered_a = filtered_a[filtered_a['CONSTRUCTION_TYPE'].str.contains(type_target, na=False)] if filtered_a.empty: return pd.Series([None, None]) # 3. 处理CONSTRUCTION_TYPE_FAMILY条件 family_include, family_exclude, family_fuzzy = parse_family_condition(b_row['CONSTRUCTION_TYPE_FAMILY']) # 正向匹配:命中include列表 或 匹配模糊正则 include_mask = filtered_a['CONSTRUCTION_TYPE_FAMILY'].isin(family_include) for pattern in family_fuzzy: include_mask |= filtered_a['CONSTRUCTION_TYPE_FAMILY'].str.match(pattern, na=False) # 排除匹配:不在exclude列表中 exclude_mask = ~filtered_a['CONSTRUCTION_TYPE_FAMILY'].isin(family_exclude) final_filtered = filtered_a[include_mask & exclude_mask] if final_filtered.empty: return pd.Series([None, None]) # 返回第一个匹配结果的步骤数(需求不同可改成取均值/全部结果) return pd.Series([final_filtered.iloc[0]['翻新步骤数'], final_filtered.iloc[0]['预防性维护步骤数']])
步骤3:批量应用到DataFrame B
假设你的两个数据集分别为df_a和df_b,执行以下代码完成匹配:
# 给df_b新增匹配到的步骤数字段 df_b[['翻新步骤数', '预防性维护步骤数']] = df_b.apply(lambda x: match_equipment(x, df_a), axis=1)
补充说明
- 如果
CONSTRUCTOR需要模糊匹配,将第一步的==替换为str.contains(..., na=False) - 模糊匹配规则可根据实际样本调整(比如
H3xx如果限定为H3+两位数字,正则改成H3\d{2}) - 若存在多个匹配结果,可修改返回逻辑(比如取所有结果的平均值,或用
explode保留全部匹配项)
内容的提问来源于stack exchange,提问作者Taylor
相关产品推荐
相关产品推荐

