如何在Pandas中匹配评估全称/缩写并新增去重缩写列?
解决Pandas DataFrame评估名称匹配问题
问题场景
现有两个Pandas DataFrame:
names_df:存储评估工具的全称与对应缩写uses_df:存储评估工具的使用说明文本
需要给uses_df新增一列,要求:
- 检查
names_df中的评估全称/缩写是否出现在uses_df的uses列文本中 - 仅保留匹配到的评估缩写(即使只匹配到全称,也返回对应缩写)
- 同一评估的缩写仅保留一次
- 适配大数据量场景
解决方案
1. 准备示例数据
先构造可测试的样例数据,方便验证逻辑:
import pandas as pd # 评估名称映射表 names_df = pd.DataFrame({ "full_name": ["抑郁自评量表", "焦虑自评量表", "症状自评量表"], "abbreviation": ["SDS", "SAS", "SCL-90"] }) # 使用说明表 uses_df = pd.DataFrame({ "uses": [ "本次评估采用抑郁自评量表(SDS)和焦虑自评量表,用于情绪状态筛查", "仅使用SCL-90进行症状评估,未涉及其他量表", "未使用任何评估工具" ] })
2. 构建匹配映射与正则模式
为了高效匹配,先建立全称/缩写→缩写的映射字典,同时生成包含所有匹配项的正则表达式(自动转义特殊字符,避免匹配错误):
import re # 构建名称到缩写的双向映射 name_to_abbr = {} for _, row in names_df.iterrows(): full_name = row["full_name"] abbr = row["abbreviation"] name_to_abbr[full_name] = abbr name_to_abbr[abbr] = abbr # 按字符串长度降序排序,避免短字符串优先匹配(比如缩写被包含在全称里的情况) sorted_keys = sorted(name_to_abbr.keys(), key=lambda x: -len(x)) # 生成正则匹配模式 pattern = re.compile("|".join(re.escape(key) for key in sorted_keys))
3. 批量提取匹配的缩写
定义处理函数,对每一行文本提取匹配项、去重后合并成字符串,再批量应用到uses_df:
def get_matched_abbrs(text): # 提取所有匹配的名称/缩写 matches = pattern.findall(text) # 映射为缩写并去重 unique_abbrs = list({name_to_abbr[match] for match in matches}) # 返回格式化后的结果,无匹配则返回空字符串 return ", ".join(unique_abbrs) if unique_abbrs else "" # 生成新列 uses_df["matched_abbreviations"] = uses_df["uses"].apply(get_matched_abbrs)
4. 大数据量优化方案
如果数据量极大,apply效率不足,可以用Pandas原生的字符串方法结合分组处理:
# 批量提取所有匹配项 uses_df["temp_matches"] = uses_df["uses"].str.findall(pattern) # 映射为缩写并去重合并 uses_df["matched_abbreviations"] = uses_df["temp_matches"].apply( lambda x: ", ".join({name_to_abbr[m] for m in x}) if x else "" ) # 删除临时列 uses_df = uses_df.drop("temp_matches", axis=1)
5. 结果展示
处理后的uses_df如下:
print(uses_df)
输出:
uses matched_abbreviations 0 本次评估采用抑郁自评量表(SDS)和焦虑自评量表,用于情绪状态筛查 SDS, SAS 1 仅使用SCL-90进行症状评估,未涉及其他量表 SCL-90 2 未使用任何评估工具
额外适配技巧
- 大小写不敏感匹配:如果文本中存在大小写混合的情况,修改正则编译规则并调整映射字典:
# 构建小写键的映射字典 name_to_abbr_lower = {k.lower(): v for k, v in name_to_abbr.items()} # 编译忽略大小写的正则 pattern = re.compile("|".join(re.escape(key) for key in sorted_keys), re.IGNORECASE) def get_matched_abbrs_case_insensitive(text): matches = pattern.findall(text.lower()) unique_abbrs = list({name_to_abbr_lower[match] for match in matches}) return ", ".join(unique_abbrs) if unique_abbrs else ""
内容的提问来源于stack exchange,提问作者mamoset
相关产品推荐
相关产品推荐

