Pandas DataFrame多列拼接去重异常及效率优化问题
Pandas多列邮箱去重优化方案
问题场景
需要为DataFrame中每个客户合并email1、email2、email3三列的邮箱地址,要求:
- 忽略大小写差异
- 去除重复值
- 处理空值(NaN)
- 适配50万+行的大数据集,保证效率
示例DataFrame:
import pandas as pd import numpy as np df = pd.DataFrame({'customer id':[1,2,3,4,5], 'email1':['ex11@email.com',np.nan,'ex31@email.com',np.nan, np.nan], 'email2':['ex11@email.com' ,np.nan,'Ex3@email.com','ex4@email.com', np.nan], 'email3':['ex12@email.com',np.nan,'ex3@email.com','ex4@email.com', 'ex5@email.com']})
对应的数据集内容:
customer id email1 email2 email3 0 1 ex11@email.com ex11@email.com ex12@email.com 1 2 NaN NaN NaN 2 3 ex31@email.com Ex3@email.com ex3@email.com 3 4 NaN ex4@email.com ex4@email.com 4 5 NaN NaN ex5@email.com
原方案的问题
- 首次尝试拼接列:
df['ALL_EMAILS'] = df[['email1','email2','email3']].apply(lambda x: ', '.join(x[x.notnull()]), axis = 1)
在50万+行数据上耗时约3分钟,效率极低。
- 后续编写
checkemail函数去重,但结果错误:
def checkemail(x): if x: lower_x = x.lower() y= lower_x.split(',') return set(y)
问题点:
- 分割后字符串带空格(如
' ex11@email.com'和'ex11@email.com'被视为不同值),导致重复 - 空值处理不完善,出现
None结果 - 整体效率仍未优化
错误结果示例:
ALL_EMAILS 0 { ex11@email.com, ex11@email.com, ex12@email.com} 1 None 2 { ex3@email.com, ex31@email.com} 3 { ex4@email.com, ex4@email.com} 4 {ex5@email.com}
优化解决方案
方法一:向量化操作(高效适配大数据集)
利用Pandas的向量化API替代apply,大幅提升速度:
# 选择邮箱列,统一转小写,保留空值为NaN email_cols = df[['email1', 'email2', 'email3']].apply(lambda col: col.str.lower()) # 每行过滤空值后转集合去重,再转为逗号分隔字符串 df['ALL_EMAILS'] = email_cols.apply(lambda row: ', '.join(set(row.dropna())), axis=1) # 处理全空行,替换为空值而非空字符串 df['ALL_EMAILS'] = df['ALL_EMAILS'].replace('', np.nan)
说明:
- 先统一转小写,从根源避免大小写差异导致的重复
row.dropna()直接过滤空值,无需手动判断- 直接对非空值转集合去重,规避分割空格的问题
- 向量化操作比自定义函数效率高数倍,50万行数据可控制在数十秒内完成
方法二:优化自定义函数(兼容旧代码场景)
如果必须使用自定义函数,修正空格和空值问题:
def checkemail(row): # 收集非空邮箱,转小写并去除前后空格 emails = [str(e).strip().lower() for e in row if pd.notna(e)] # 去重后拼接,空列表返回NaN return ', '.join(set(emails)) if emails else np.nan df['ALL_EMAILS'] = df[['email1', 'email2', 'email3']].apply(checkemail, axis=1)
说明:
- 遍历行内元素时直接处理空格和大小写,避免后续分割问题
- 明确判断空列表情况,返回
np.nan而非None - 逻辑简洁且无重复值问题
最终效果
处理后正确结果:
customer id email1 email2 email3 ALL_EMAILS 0 1 ex11@email.com ex11@email.com ex12@email.com ex12@email.com, ex11@email.com 1 2 NaN NaN NaN NaN 2 3 ex31@email.com Ex3@email.com ex3@email.com ex31@email.com, ex3@email.com 3 4 NaN ex4@email.com ex4@email.com ex4@email.com 4 5 NaN NaN ex5@email.com ex5@email.com
内容的提问来源于stack exchange,提问作者MTALY
相关产品推荐
相关产品推荐

