Pandas子串匹配实现多值关键词标注(Python)
高效匹配Pandas DataFrame标签的解决方案(适用于大规模数据集)
针对大规模数据集,逐行循环匹配关键词效率极低,我们需要采用向量化或优化的关键词匹配方法。以下是两种实用方案,可根据你的关键词数量规模选择:
方案一:基于正则表达式的向量化匹配(适合中小规模关键词集)
这种方法利用Pandas的向量化字符串操作,避免Python层面的逐行循环,性能优于普通迭代。
步骤说明:
- 构建关键词到标签的映射(用集合避免单个关键词内的标签重复)
- 生成匹配所有关键词的正则表达式(转义特殊字符防止正则语法冲突)
- 提取每个短语中所有匹配的关键词
- 聚合标签并去重,合并回原DataFrame
代码示例:
import pandas as pd import re # 示例数据 df1 = pd.DataFrame({'phrase': ['苹果派配苹果', '香蕉面包', '樱桃挞', '橙汁', '混合莓果冰沙']}) df2 = pd.DataFrame({ 'keyword': ['苹果', '香蕉', '派', '挞', '莓果'], 'tag1': ['水果', '水果', '烘焙', '烘焙', '水果'], 'tag2': ['甜点', '甜点', '甜点', '甜点', '饮品'] }) # 1. 构建关键词-标签映射(集合自动去重单个关键词的重复标签) keyword_tag_map = df2.set_index('keyword').apply( lambda row: {row['tag1'], row['tag2']}, axis=1 ).to_dict() # 2. 生成正则模式(转义关键词中的特殊字符) escaped_keywords = [re.escape(k) for k in keyword_tag_map.keys()] # 若需匹配完整单词,添加\b边界:pattern = r'\b(' + '|'.join(escaped_keywords) + r')\b' pattern = '|'.join(escaped_keywords) # 3. 提取所有匹配的关键词 matches = df1['phrase'].str.extractall(f'({pattern})')[0].reset_index() matches.columns = ['phrase_idx', 'match_order', 'keyword'] # 4. 聚合标签并去重 matches['tags'] = matches['keyword'].map(keyword_tag_map) aggregated_tags = matches.groupby('phrase_idx')['tags'].apply( lambda x: set().union(*x) # 合并所有匹配关键词的标签并去重 ).reset_index() # 转换为可读字符串,空匹配则设为空字符串 aggregated_tags['tags_str'] = aggregated_tags['tags'].apply( lambda x: ', '.join(sorted(x)) if x else '' ) # 合并回原DataFrame df1 = df1.merge( aggregated_tags[['phrase_idx', 'tags_str']], left_index=True, right_on='phrase_idx', how='left' ).drop('phrase_idx', axis=1).fillna({'tags_str': ''}) print(df1)
方案二:基于Flashtext的匹配(适合大规模关键词集)
当关键词数量超过1万条时,正则表达式的性能会显著下降,此时Flashtext是更好的选择。它基于字典树(Trie)结构,匹配时间复杂度为O(n)(n为文本长度),与关键词数量无关,效率远超正则。
步骤说明:
- 安装并导入Flashtext库
- 初始化关键词处理器,添加关键词及对应标签集合
- 批量提取每个短语的匹配标签,聚合去重
代码示例:
import pandas as pd from flashtext import KeywordProcessor # 示例数据同方案一 df1 = pd.DataFrame({'phrase': ['苹果派配苹果', '香蕉面包', '樱桃挞', '橙汁', '混合莓果冰沙']}) df2 = pd.DataFrame({ 'keyword': ['苹果', '香蕉', '派', '挞', '莓果'], 'tag1': ['水果', '水果', '烘焙', '烘焙', '水果'], 'tag2': ['甜点', '甜点', '甜点', '甜点', '饮品'] }) # 1. 初始化关键词处理器(case_sensitive=False表示不区分大小写) kp = KeywordProcessor(case_sensitive=False) # 2. 添加关键词及对应标签集合 for _, row in df2.iterrows(): kp.add_keyword(row['keyword'], {row['tag1'], row['tag2']}) # 若需匹配完整单词,添加word_boundaries=True: # kp.add_keyword(row['keyword'], {row['tag1'], row['tag2']}, word_boundaries=True) # 3. 提取并聚合标签 df1['tags'] = df1['phrase'].apply( lambda x: set().union(*kp.extract_keywords(x)) if kp.extract_keywords(x) else set() ) # 转换为可读字符串 df1['tags_str'] = df1['tags'].apply( lambda x: ', '.join(sorted(x)) if x else '' ) print(df1)
关键注意事项:
- 特殊字符处理:正则方案中用
re.escape()转义关键词中的特殊字符(如.、*等),避免正则语法错误;Flashtext会自动处理特殊字符。 - 大小写敏感性:两种方案都可通过参数设置是否区分大小写。
- 完整单词匹配:若需匹配完整单词而非子串,正则方案添加
\b边界,Flashtext设置word_boundaries=True。 - 空值处理:最终结果中无匹配的短语标签设为空字符串,符合需求。
内容的提问来源于stack exchange,提问作者jonny
相关产品推荐
相关产品推荐

