Python按阈值筛选Jaccard相似度行的问题修正
解决Jaccard相似度筛选问题(排除自身匹配、过滤无结果行)
问题分析
你的代码存在三个核心问题:
- 未排除自身匹配:遍历所有行时包含了当前行与自身的对比,当阈值设为>0.95时,自身相似度为1,会被纳入结果。
- 保留了无符合条件的行:无论当前行是否有匹配的其他行,都会被添加到输出DataFrame,导致出现多余的空结果行。
- 字符串分割未处理空格:
split(',')得到的元素带空格(如['dog', ' cat']),会导致集合交集计算错误,影响Jaccard值准确性。
修正后的代码
import pandas as pd data = { 'letters': ['a', 'b', 'c', 'd'], 'animals': ['dog, cat, fish', 'cat, fish', 'dog, bird, fish', 'dog'] } df = pd.DataFrame(data) def jaccard(list1, list2): # 去除每个元素的空格,避免因空格导致集合匹配错误 set1 = set(item.strip() for item in list1) set2 = set(item.strip() for item in list2) intersection = len(set1 & set2) union = len(set1 | set2) # 处理union为0的极端情况(当前数据不会出现,增加健壮性) return float(intersection) / union if union != 0 else 0.0 out_data = [] threshold_low = 0.3 threshold_high = 0.4 for ind1, r1 in df.iterrows(): matched_ids = [] # 遍历其他行,跳过自身 for ind2, r2 in df.iterrows(): if ind1 == ind2: continue # 分割动物列表并计算相似度 sim = jaccard(r1['animals'].split(','), r2['animals'].split(',')) if threshold_low < sim <= threshold_high: matched_ids.append(r2['letters']) # 仅当有匹配结果时才添加到输出 if matched_ids: out_data.append({ 'letters': r1['letters'], 'animals': r1['animals'], 'sub-animal-letters': ','.join(matched_ids) }) # 转换为DataFrame并输出 out_df = pd.DataFrame(out_data) print(out_df)
代码说明
- 处理空格问题:在Jaccard函数中用
item.strip()去除每个动物名称的前后空格,确保集合对比准确。 - 排除自身匹配:添加
if ind1 == ind2: continue跳过当前行与自身的对比。 - 过滤无结果行:只有当
matched_ids不为空时,才将该行加入输出列表,避免多余空行。 - 优化Jaccard计算:用集合运算符
&和|替代intersection和union方法,代码更简洁。
运行结果(阈值0.3~0.4)
| letters | animals | sub-animal-letters |
|---|---|---|
| a | dog, cat, fish | d |
| c | dog, bird, fish | d |
当阈值设为>0.95时,不会出现自身匹配的结果,因为已经跳过了自身对比逻辑。
内容的提问来源于stack exchange,提问作者abcabc
相关产品推荐
相关产品推荐

