如何逐行匹配search_words与text_to_search过滤Pandas DataFrame
问题分析与解决方案
现有方法的问题
- 第一种方法失效原因:你用
x.search_words in x['text_to_search']是把search_words整串当成单个匹配项,只有当text_to_search完整包含整个search_words字符串时才会命中。如果search_words是多个词/短语的组合,这种逻辑完全不符合“任意词匹配”的需求。 - 第二种方法误匹配原因:把所有行的
search_words合并成全局正则式,相当于用所有行的关键词去匹配每一行的text_to_search,自然会出现跨行误判——某行的文本只要包含其他行的关键词就会被错误选中。
正确实现方案
根据search_words的存储格式,分两种场景处理:
场景1:search_words是用分隔符(逗号/空格)分隔的字符串
比如search_words的值是"苹果, 香蕉派, 橙子",先拆分关键词,再逐行检查任意关键词是否完整出现在对应text_to_search中:
import pandas as pd def check_keyword_match(row): # 处理空值:若search_words为空,直接返回False if pd.isna(row['search_words']): return False # 拆分关键词,去除每个词前后的空格,分隔符根据实际情况调整,比如空格就用split() keywords = [kw.strip() for kw in row['search_words'].split(',')] # 检查任意关键词是否完整出现在text_to_search中 return any(kw in row['text_to_search'] for kw in keywords) # 过滤符合条件的行 df_filtered = df1[df1.apply(check_keyword_match, axis=1)]
如果需要严格匹配独立的词/短语(避免部分匹配,比如关键词"派"不会匹配"派送"),可以用正则边界匹配,注意转义关键词中的特殊字符:
import re def check_exact_match(row): if pd.isna(row['search_words']): return False keywords = [kw.strip() for kw in row['search_words'].split(',')] # 对每个关键词转义,避免正则语法冲突,然后用|连接成正则式 pattern = '|'.join(re.escape(kw) for kw in keywords) # 匹配独立短语(若短语含空格,\b边界失效,可改用前后非单词字符匹配) return bool(re.search(r'(?:^|\W){}(?:$|\W)'.format(pattern), row['text_to_search'])) df_filtered = df1[df1.apply(check_exact_match, axis=1)]
场景2:search_words是列表类型
如果search_words已经是列表(比如["苹果", "香蕉派"]),逻辑更简单:
df_filtered = df1[df1.apply(lambda x: any(kw in x['text_to_search'] for kw in x['search_words']), axis=1)]
性能优化提示
如果是超大型DataFrame,apply效率可能偏低,可以用swifter库加速(自动选择矢量化或并行处理):
import swifter df_filtered = df1[df1.swifter.apply(check_keyword_match, axis=1)]
内容的提问来源于stack exchange,提问作者deric
相关产品推荐
相关产品推荐

