NER场景下带位置与相似度返回的近似字符串匹配替换高效方法
你需要的功能可以直接通过RapidFuzz库实现,不需要自己手动写滑动窗口逻辑,这个库本身支持返回匹配的相似度、起止位置,完全匹配你的需求。
实现方案
1. 依赖安装
执行命令安装RapidFuzz:pip install rapidfuzz
2. 核心代码实现
from rapidfuzz import process, fuzz def fuzzy_entity_replace(input_text: str, entity_mapping: dict, similarity_threshold: int = 80) -> str: """ 模糊匹配实体并替换为指定标签 :param input_text: 预处理后的小写输入文本 :param entity_mapping: 实体到替换标签的映射,比如 {"google": "COMPANY_NAME"} :param similarity_threshold: 匹配相似度阈值,0-100,低于阈值的匹配会被忽略 :return: 替换后的文本 """ # 收集所有合法匹配 match_records = [] for entity, replace_tag in entity_mapping.items(): # 查找当前实体在文本中的匹配结果,自动过滤低于阈值的结果 match_results = process.extract( query=entity, choices=[input_text], scorer=fuzz.partial_ratio, score_cutoff=similarity_threshold ) if not match_results: continue # 提取匹配的分数和起止位置 similarity_score, (start_idx, end_idx) = match_results[0][1], match_results[0][2] match_records.append((start_idx, end_idx, similarity_score, replace_tag)) # 处理匹配重叠的情况:优先保留分数更高、长度更长的匹配 match_records.sort(key=lambda x: (-x[2], -(x[1] - x[0]))) used_indexes = set() valid_matches = [] for start, end, score, tag in match_records: # 检查当前匹配区间是否已经被其他更高优先级的匹配占用 if not any(idx in used_indexes for idx in range(start, end)): valid_matches.append((start, end, tag)) # 标记占用的位置 for idx in range(start, end): used_indexes.add(idx) # 从后往前替换,避免前面的替换改变后面字符的索引位置 valid_matches.sort(reverse=True) result_text = input_text for start, end, tag in valid_matches: result_text = result_text[:start] + tag + result_text[end:] return result_text
3. 使用示例
首先定义你的实体映射表:
company_entity_map = { "google": "COMPANY_NAME", "microsoft": "COMPANY_NAME", "facebook": "COMPANY_NAME", "international business machine": "COMPANY_NAME" }
测试效果:
# 测试1:普通匹配 print(fuzzy_entity_replace("s/he works at google", company_entity_map)) # 输出:s/he works at COMPANY_NAME # 测试2:多实体匹配 print(fuzzy_entity_replace("google and microsoft are big companies", company_entity_map)) # 输出:COMPANY_NAME and COMPANY_NAME are big companies # 测试3:拼写错误的模糊匹配 print(fuzzy_entity_replace("i work at internatonal business machin", company_entity_map, similarity_threshold=75)) # 输出:i work at COMPANY_NAME
优化建议
如果你的实体量级超过1万条,或者需要处理大批量文本,可以做以下优化:
- 用
process.cdist批量计算所有实体和所有输入文本的相似度,比逐一遍历实体快3-10倍 - 如果匹配精度要求更高,可以先对文本和实体做分词,改为基于token序列的模糊匹配,减少无关字符的干扰
- 对于长度差异极大的实体,可以先按实体的token长度分组,减少匹配时的无效计算
内容的提问来源于stack exchange,提问作者hafiz031
相关产品推荐
相关产品推荐

