Python中如何将DataFrame每行与字典列表匹配并添加标记列?
解决方案:DataFrame与规则字典列表的匹配实现
问题原因分析
你遇到的TypeError: unhashable type: 'dict'错误,是因为尝试将不可哈希的字典对象作为匹配的键使用(比如把整行字典直接拿去做哈希查找)。字典属于可变类型,无法被哈希,因此会触发这个错误。
两种可行实现思路
思路1:直接用Pandas逐行处理(推荐)
无需转换DataFrame格式,直接利用apply逐行遍历,结合自定义匹配函数完成规则校验,逻辑更灵活,能应对部分列匹配、集合交集匹配等复杂场景。
步骤与代码示例
- 定义规则列表(可根据实际需求调整结构):
import pandas as pd # 示例规则列表:每个规则包含匹配条件和描述 rules_list = [ {"condition": {"code1": ("VA", "HC"), "code4": float("nan")}, "desc": "rules1"}, {"condition": {"code2": ("103", "104"), "code4": "computerscience"}, "desc": "rules2"}, {"condition": {"code6": ("594",)}, "desc": "rules12"}, # 补充其他规则... ]
- 编写匹配函数:
def match_single_row(row, rules): """检查单行数据是否匹配任意规则,返回匹配状态和规则描述""" for rule in rules: match_flag = True for col, expected_val in rule["condition"].items(): # 处理空值(nan)的匹配逻辑 if pd.isna(row[col]): if not pd.isna(expected_val): match_flag = False break else: # 处理集合/元组类型的匹配(示例为交集匹配,可改为完全匹配) if isinstance(expected_val, (tuple, list, set)): if not set(row[col]) & set(expected_val): match_flag = False break # 处理单一值的匹配 else: if row[col] != expected_val: match_flag = False break if match_flag: return (True, rule["desc"]) # 无匹配规则时返回默认值 return (False, "None")
- 应用到DataFrame:
# 假设df是你的原始数据DataFrame df[["isHit", "rules_desc"]] = df.apply( lambda row: match_single_row(row, rules_list), axis=1, result_type="expand" )
思路2:转换为字典列表后处理(适合完全匹配场景)
如果必须转换为字典列表,需要先将行数据和规则条件转换为可哈希的结构(比如元组、frozenset),避免字典不可哈希的问题。这种方式仅适合全列完全匹配的场景。
步骤与代码示例
- 定义哈希转换函数:
def to_hashable(item): """将不可哈希的对象转换为可哈希类型""" if pd.isna(item): return None elif isinstance(item, (tuple, list)): return frozenset(item) else: return item def row_to_hashable(row_dict): """将整行字典转换为可哈希的元组""" return tuple(sorted((k, to_hashable(v)) for k, v in row_dict.items()))
- 构建规则哈希映射:
rules_map = {} for rule in rules_list: # 将规则条件转换为可哈希结构 hashable_condition = row_to_hashable(rule["condition"]) rules_map[hashable_condition] = (True, rule["desc"])
- 处理字典列表并匹配:
# 将DataFrame转为字典列表 row_dicts = df.to_dict("records") # 逐行匹配 results = [] for row in row_dicts: hashable_row = row_to_hashable(row) results.append(rules_map.get(hashable_row, (False, "None"))) # 将结果合并回DataFrame df[["isHit", "rules_desc"]] = results
方案选择建议
- 若需处理部分列匹配、集合交集/包含匹配等复杂逻辑,优先使用思路1(Pandas直接处理),代码可读性和灵活性更强。
- 若仅需全列完全匹配,可使用思路2,性能略优(但差异不大)。
内容的提问来源于stack exchange,提问作者Hamilton
相关产品推荐
相关产品推荐

