You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

原方案的问题

  1. 首次尝试拼接列:
df['ALL_EMAILS'] = df[['email1','email2','email3']].apply(lambda x: ', '.join(x[x.notnull()]), axis = 1)

在50万+行数据上耗时约3分钟,效率极低。

  1. 后续编写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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 06:05:37