Pandas处理超范围日期(OutOfBoundsDatetime)时如何保留原日期而非转为NaT?
我懂你的困扰!碰到这种超出nanosecond精度datetime范围的日期,既不想把有效数据丢成NaT,又要完成按日期去重的核心需求,确实挺头疼的。下面给你几个实用的解决方案,都是针对你的函数直接修改的,你可以根据自己的Pandas版本和日期格式来选:
方法一:用PyArrow引擎解析日期(Pandas 2.0+ 推荐)
如果你用的是Pandas 2.0及以上版本,直接给pd.to_datetime加个engine='pyarrow'参数就行。PyArrow的datetime类型支持的范围比默认的nanosecond精度大得多,轻松覆盖3036年这种远未来日期,而且完全不需要丢数据:
修改你函数里的日期转换行,整个函数调整后如下:
def remove_duplicates_based_on_keydate(df, id_col, date_col): df = df.copy() # 用PyArrow引擎解析,支持超宽日期范围 df.loc[:, date_col] = pd.to_datetime(df[date_col], engine='pyarrow') # Sort by the date column in descending order df_sorted = df.sort_values(by=date_col, ascending=False) # Drop duplicates, keeping the first occurrence (latest date) df_unique = df_sorted.drop_duplicates(subset=id_col, keep='first') # Sort again by id_col and reset index df_unique = df_unique.sort_values(by=id_col).reset_index(drop=True) return df_unique
方法二:转成低精度的datetime类型(兼容旧版Pandas)
如果你的Pandas版本低于2.0,不支持PyArrow引擎,可以把日期转成datetime64[us](微秒精度)类型——它的范围从公元1年到290308年,完全能hold住3036年。具体做法是先把日期解析成Python原生的datetime对象,再转成微秒精度的datetime类型:
先安装python-dateutil(如果没装的话执行pip install python-dateutil),然后修改函数:
from dateutil import parser def remove_duplicates_based_on_keydate(df, id_col, date_col): df = df.copy() # 先解析为Python原生datetime对象,再转成微秒精度的datetime64类型 df.loc[:, date_col] = df[date_col].apply(lambda x: parser.parse(x)).astype('datetime64[us]') # Sort by the date column in descending order df_sorted = df.sort_values(by=date_col, ascending=False) # Drop duplicates, keeping the first occurrence (latest date) df_unique = df_sorted.drop_duplicates(subset=id_col, keep='first') # Sort again by id_col and reset index df_unique = df_unique.sort_values(by=id_col).reset_index(drop=True) return df_unique
方法三:直接按字符串排序(仅适用于ISO标准格式日期)
如果你的日期列是严格的YYYY-MM-DD这种ISO格式,其实完全不用转成datetime类型——因为这种格式的字符串字典序和日期的时间序是完全一致的,直接按字符串排序去重就行,彻底避开datetime转换的坑:
修改后的函数如下:
def remove_duplicates_based_on_keydate(df, id_col, date_col): df = df.copy() # 不用转datetime,直接按字符串排序(仅适用于YYYY-MM-DD这类标准格式) df_sorted = df.sort_values(by=date_col, ascending=False) # Drop duplicates, keeping the first occurrence (latest date) df_unique = df_sorted.drop_duplicates(subset=id_col, keep='first') # Sort again by id_col and reset index df_unique = df_unique.sort_values(by=id_col).reset_index(drop=True) return df_unique
这个方法最轻便,但要注意:如果你的日期格式是DD/MM/YYYY这类非ISO格式,字符串排序结果会和日期顺序不符,就不能用了。
备注:内容来源于stack exchange,提问作者MPathan

