使用.apply()清洗DataFrame邮箱:数据未更新问题
很高兴看到你已经修正代码让.apply()生效了!既然你想继续用.apply()来巩固这个方法,同时也想了解更高效的替代方案,我来帮你一步步梳理:
一、优化后的.apply()写法
首先要修正一个小细节:你原来的domains是一个完整字符串,得拆分成列表才能逐个遍历检查域名:
domains = 'gmail.com hotmail.com yahoo.com hotmail.co.uk'.split()
然后调整清洗函数,找到匹配的域名后就直接处理返回,避免不必要的循环:
def cleaning(email): for domain in domains: if domain in email: # 检查域名前一位是不是@ if email[-len(domain)-1] != '@': # 拆分用户名和域名,拼接@ username = email[:-len(domain)] return f"{username}@{domain}" # 如果没有匹配到域名或者已经有@,直接返回原邮箱 return email
调用.apply()处理邮箱列:
df['email'] = df['email'].apply(cleaning) print(df)
输出结果会完全符合你的预期:
email col2 0 foobar@gmail.com make 1 barfoo@gmail.com a 2 hellothere@gmail.com data 3 myemail@hotmail.com frame
二、更高效的非.apply()方案:正则表达式
.apply()是逐行处理,当DataFrame数据量很大时,效率会比较低。用Pandas的字符串方法结合正则表达式,能实现向量级别的处理,速度快很多:
import re # 构造正则模式:匹配域名且前面没有@ domain_pattern = r'(?<!@)(gmail\.com|hotmail\.com|yahoo\.com|hotmail\.co\.uk)' df['email'] = df['email'].str.replace(domain_pattern, r'@\1', regex=True)
正则解释:
(?<!@):负向零宽断言,确保匹配到的域名前面没有@符号(gmail\.com|...):分组匹配所有目标域名(注意.要转义成\.,否则会匹配任意字符)r'@\1':替换为@加上分组匹配到的域名
这个方法和.apply()的结果完全一致,但处理大数据集时性能会好很多。
三、为什么最初的函数没生效?
结合你提到的@Tomaz Gandor指出的错误,大概率是因为domains没有拆分成列表——原来的写法会让循环遍历字符串的每个字符,而不是逐个域名检查,所以函数找不到匹配的域名,自然不会修改邮箱。修正后就能正常工作啦~
内容的提问来源于stack exchange,提问作者SCool
相关产品推荐
相关产品推荐

