Pandas清理test_no重复值并匹配共享test_no的my_id
解决方案
1. 清理test_no字段的重复值(含空格、NaN)
原代码失效的核心原因是未处理每个测试编号前后的空格,以及未过滤拆分后产生的空值(比如原字符串中的连续逗号或纯空格项)。以下是完善的清理逻辑:
import pandas as pd # 示例DataFrame(可替换为你的真实数据) df = pd.DataFrame({ 'my_id': [1, 2, 3, 4, 5], 'test_no': ['A1, A2, A1', 'B1,B2, B3,B2', None, 'C1, ,C2,C1', 'D1'] }) def clean_test_no(x): # 处理NaN/空值情况 if pd.isna(x) or str(x).strip() == '': return '' # 拆分字符串,去除每个项的空格,过滤空字符串 items = [item.strip() for item in str(x).split(',') if item.strip()] # 去重并保留原始出现顺序(Python 3.7+ 字典默认有序) unique_items = list(dict.fromkeys(items)) return ','.join(unique_items) # 生成清理后的字段 df['cleaned_test_no'] = df['test_no'].apply(clean_test_no)
逻辑说明:
- 先判断并处理
NaN或纯空字符串,返回空值避免后续报错 - 拆分后对每个测试编号做
strip()去除首尾空格,同时过滤掉拆分后产生的空项(比如原字符串中的, ,会拆出空字符串) - 使用
dict.fromkeys()去重,相比set()能保留测试编号的原始出现顺序
2. 匹配共享相同test_no的my_id
需要先将清理后的多值test_no拆分为单个测试编号,再通过分组收集关联的my_id,最后匹配回原DataFrame:
# 将cleaned_test_no拆分为单个测试项,展开DataFrame test_id_expanded = df.assign(test_item=df['cleaned_test_no'].str.split(',')).explode('test_item') # 过滤空的测试项 test_id_expanded = test_id_expanded[test_id_expanded['test_item'] != ''] # 按测试项分组,收集对应的my_id列表 shared_test_map = test_id_expanded.groupby('test_item')['my_id'].agg(list).reset_index() # 筛选出有多个my_id的测试项(即被共享的test_no) shared_test_map = shared_test_map[shared_test_map['my_id'].apply(len) > 1] # 将共享的my_id匹配回原DataFrame(去除当前行自身的my_id) def get_shared_ids(row): test_items = row['cleaned_test_no'].split(',') shared_ids = [] for item in test_items: if item in shared_test_map['test_item'].values: ids = shared_test_map[shared_test_map['test_item'] == item]['my_id'].iloc[0] # 排除当前行自己的id shared_ids.extend([id for id in ids if id != row['my_id']]) # 去重并返回 return list(dict.fromkeys(shared_ids)) df['shared_my_ids'] = df.apply(get_shared_ids, axis=1)
结果说明:
- 最终
df会新增cleaned_test_no(去重后的测试编号)和shared_my_ids(当前my_id共享测试编号的其他id列表)两个字段 - 如果某个
my_id没有共享任何测试编号,shared_my_ids会返回空列表
内容的提问来源于stack exchange,提问作者Ash
相关产品推荐
相关产品推荐

