在DataFrame文本列匹配多字符串并累加对应分数的高效实现方法
高效实现Pandas子串匹配并累加分数
当然有更简洁高效的实现方式!你当前用的双重iterrows()循环在数据量较大时会非常慢,因为它是逐行的Python级别迭代。我们可以利用Pandas的向量化操作来大幅提升效率,下面提供两种实用方案:
方案1:使用apply结合布尔索引(简洁易读)
这种方法代码直观,适合中小规模数据集:
import pandas as pd # 初始化示例数据 df1 = pd.DataFrame({ 'ID':[1,2,3,4,5,6], 'Texts':['this is a string', 'here we have another string', 'this one is completly different', 'one more', 'this is one more', 'and the last one'], 'c':['C','C','C','C','C','C'], 'd':['D','D','D','D','NaN','NaN'] }) df2 = pd.DataFrame({ 'SubString':['This', 'one', 'this is', 'is one'], 'Score':[0.5, 0.2, 0.75, -0.5] }) # 为df1添加Score列 df1['Score'] = df1['Texts'].apply( lambda txt: df2[df2['SubString'].apply(lambda s: s in txt)]['Score'].sum() ) print(df1)
这段代码对df1的每个文本,筛选出df2中满足“子串存在于文本”的行,然后累加对应的分数。
方案2:广播+矩阵运算(性能最优)
如果你的数据集很大,推荐这种方法——利用NumPy的向量化计算,完全避免Python层面的循环,速度提升非常明显:
# 创建布尔匹配矩阵:每行对应df1的文本,每列对应df2的子串,值为子串是否在文本中 matches = df1['Texts'].apply(lambda x: df2['SubString'].apply(lambda y: y in x)).values # 通过矩阵乘法直接计算每个文本的总分 df1['Score'] = matches @ df2['Score'].values print(df1)
扩展:忽略大小写匹配
如果需要不区分大小写的匹配,可以将文本和子串统一转为小写:
# 方案2的大小写不敏感版本 matches = df1['Texts'].str.lower().apply( lambda x: df2['SubString'].str.lower().apply(lambda y: y in x) ).values df1['Score'] = matches @ df2['Score'].values
为什么这两种方法更好?
- 避免了
iterrows()的低效逐行迭代:iterrows()会把每一行转为Python对象,速度远低于Pandas/NumPy的向量化操作。 - 代码更简洁:去掉了嵌套循环,逻辑一目了然。
- 性能差距显著:当
df1有1000行、df2有100行时,向量化方法的速度会比双重循环快几十倍甚至上百倍。
内容的提问来源于stack exchange,提问作者Fernando S. Peregrino
相关产品推荐
相关产品推荐

