Pandas DataFrame日期转换异常问题排查与解决求助
问题描述
尝试转换DataFrame的['Date','Value Dt']两列为日期格式时出现异常:2023年5月1日至12日的部分日期被错误按%m/%d/%Y解析,其余日期(包括5月13日后)则正常按%d/%m/%Y解析。使用的转换代码如下:
columns_to_convert_to_date= ['Date','Value Dt'] regex_pattern = r'\d{2}/\d{2}/\d{4}' for column in columns_to_convert_to_date: full_bank_df_hdfc[column] = full_bank_df_hdfc[column].apply(lambda x: pd.to_datetime(x, format='%d/%m/%Y', errors='coerce') if re.match(regex_pattern, str(x)) else pd.to_datetime(x, errors='coerce'))
单独使用pd.to_datetime(full_bank_df_hdfc['Date'],format='%d/%m/%y', errors='coerce')能得到目标输出,但会将已有的datetime格式行转为NaT。
异常原因分析
- 混合日期格式触发自动推断错误:原始数据中5月1日-12日的日期字符串为
%m/%d/%Y格式,其余日期为%d/%m/%Y格式。当日期的日部分≤12时,pd.to_datetime的自动推断逻辑会优先按%m/%d/%Y解析(受系统locale或默认规则影响);而日部分>12时,无法按%m/%d/%Y解析,只能按%d/%m/%Y解析,因此5月13日后恢复正常。 - 现有代码的缺陷:对所有匹配正则的字符串强制用
%d/%m/%Y解析,会把%m/%d/%Y格式的日期(如05/01/2023)错误解析为2023-01-05;单独指定格式时,pd.to_datetime会将已有的datetime对象转为字符串再解析,因格式不匹配被强制转为NaT。
解决方法
方法一:自定义解析函数,分类型处理
先判断数据类型,对字符串类型先尝试%d/%m/%Y解析,失败则尝试%m/%d/%Y,直接保留已有的datetime值:
import pandas as pd import re columns_to_convert_to_date = ['Date','Value Dt'] regex_pattern = r'\d{2}/\d{2}/\d{4}' def parse_date(x): if isinstance(x, pd.Timestamp): return x x_str = str(x) if re.match(regex_pattern, x_str): # 优先尝试目标格式,失败则尝试备选格式 dt = pd.to_datetime(x_str, format='%d/%m/%Y', errors='coerce') if pd.isna(dt): dt = pd.to_datetime(x_str, format='%m/%d/%Y', errors='coerce') return dt else: return pd.to_datetime(x_str, errors='coerce') for column in columns_to_convert_to_date: full_bank_df_hdfc[column] = full_bank_df_hdfc[column].apply(parse_date)
方法二:利用多格式解析(Pandas 1.3.0+)
pd.to_datetime的format参数支持传入格式列表,会按顺序尝试解析,同时通过掩码过滤字符串类型的行,避免破坏已有的datetime值:
import pandas as pd columns_to_convert_to_date = ['Date','Value Dt'] for column in columns_to_convert_to_date: # 仅对字符串类型的行应用多格式解析 str_mask = full_bank_df_hdfc[column].apply(lambda x: isinstance(x, str)) full_bank_df_hdfc.loc[str_mask, column] = pd.to_datetime( full_bank_df_hdfc.loc[str_mask, column], format=['%d/%m/%Y', '%m/%d/%Y'], errors='coerce' ) # 对非字符串非datetime的类型尝试自动解析 other_mask = ~str_mask & ~full_bank_df_hdfc[column].apply(lambda x: isinstance(x, pd.Timestamp)) full_bank_df_hdfc.loc[other_mask, column] = pd.to_datetime( full_bank_df_hdfc.loc[other_mask, column], errors='coerce' )
补充说明:方法二更简洁,适用于Pandas版本≥1.3.0的环境,会优先使用%d/%m/%Y解析,失败时自动尝试%m/%d/%Y,无需额外的正则判断。
内容的提问来源于stack exchange,提问作者Amirul Islam
相关产品推荐
相关产品推荐

