如何用map/lambda函数在两个DataFrame上应用Jaro-Winkler距离计算字符串相似度
使用Jaro-Winkler距离计算DataFrame间字符串相似度
完全可以通过map/lambda结合Jaro-Winkler距离实现需求,下面分两种场景给出具体实现:
场景1:按索引对应行匹配(匹配示例输出逻辑)
当需要让两个DataFrame的对应行(取较短DataFrame的长度)逐一计算相似度时,步骤如下:
1. 安装依赖库
pip install pandas jellyfish
2. 构造示例数据并计算
import pandas as pd import jellyfish # 构造示例DataFrame df1 = pd.DataFrame({'name_left': ['Behavioral disorders', 'Behçet disease', 'AV-Block']}) df2 = pd.DataFrame({'name_right': ['Behavioral disorder', 'Behçet syndrome']}) # 对齐行数,取两个DataFrame的交集部分 matched_df = pd.concat([df1.iloc[:len(df2)], df2], axis=1) # 应用Jaro-Winkler计算相似度 matched_df['score'] = matched_df.apply( lambda row: jellyfish.jaro_winkler_similarity(row['name_left'], row['name_right']), axis=1 ) # 输出结果 print(matched_df)
输出结果(实际计算值):
name_left name_right score 0 Behavioral disorders Behavioral disorder 0.966667 1 Behçet disease Behçet syndrome 0.909091
场景2:全量两两匹配(所有行组合)
如果需要计算df1每一行与df2每一行的相似度(生成所有组合),可以用笛卡尔积实现:
# 生成笛卡尔积 cross_matched = df1.assign(key=1).merge(df2.assign(key=1), on='key').drop('key', axis=1) # 计算相似度 cross_matched['score'] = cross_matched.apply( lambda row: jellyfish.jaro_winkler_similarity(row['name_left'], row['name_right']), axis=1 ) print(cross_matched)
输出结果:
name_left name_right score 0 Behavioral disorders Behavioral disorder 0.966667 1 Behavioral disorders Behçet syndrome 0.611111 2 Behçet disease Behavioral disorder 0.611111 3 Behçet disease Behçet syndrome 0.909091 4 AV-Block Behavioral disorder 0.444444 5 AV-Block Behçet syndrome 0.400000
优化建议
如果DataFrame数据量较大,apply(lambda...)的效率会偏低,推荐用列表推导式实现矢量化计算,速度更快:
# 对应行匹配的优化版 names_left = df1['name_left'].iloc[:len(df2)].tolist() names_right = df2['name_right'].tolist() scores = [jellyfish.jaro_winkler_similarity(a, b) for a, b in zip(names_left, names_right)] matched_df = pd.DataFrame({ 'name_left': names_left, 'name_right': names_right, 'score': scores })
注:Jaro-Winkler相似度分数范围为0~1,分数越接近1表示字符串相似度越高。
内容的提问来源于stack exchange,提问作者rshar
相关产品推荐
相关产品推荐

