使用pandas to_datetime处理大型CSV混合日期格式时转换报错
解决Pandas分块处理大CSV时的OutOfBoundsDatetime错误
问题根源
- 索引错位误解:报错里的
position 3584是当前处理块的局部索引,不是整个CSV的全局行号,你之前查的是全局第3584行,找错了位置——真正的脏数据在当前块的第3584行,大概率是年份格式错误(比如把2020写成8020)。 - 分块写入覆盖问题:原代码中
to_csv未指定mode='a',每次处理完一个块都会覆盖之前的结果,最终只会保留最后一个块的筛选数据。 - 未处理脏数据:混合日期格式转换时,存在超出Pandas支持范围的无效日期(Pandas支持的时间范围为1677-2262年),直接转换会触发报错中断。
修正方案
步骤1:定位脏数据
在分块处理时捕获错误,直接定位当前块内的脏数据行:
import pandas as pd path_contracts = "your_contracts.csv" name_date_end = "your_date_column_name" date_report = pd.to_datetime("2020-01-01") # 替换为你的基准日期 output = "Base_Filtered.csv" reader = pd.read_csv(path_contracts, sep="|", header=0, low_memory=False, chunksize=1000000) first_chunk = True # 控制表头只写入一次 for chunk_idx, contracts in enumerate(reader): print(f"Processing chunk {chunk_idx+1}") try: # 保留原始日期值用于排查 contracts[f"{name_date_end}_raw"] = contracts[name_date_end] contracts[name_date_end] = pd.to_datetime(contracts[name_date_end], dayfirst=True, format='mixed') # 筛选未过期合同 contracts = contracts[(contracts[name_date_end] >= date_report)] except Exception as e: # 提取错误行的局部索引并打印脏数据 error_pos = str(e).split("position ")[-1].strip() if error_pos.isdigit(): error_pos = int(error_pos) print(f"脏数据在块{chunk_idx+1}的局部行{error_pos}:{contracts.at[error_pos, name_date_end]}") continue # 写入CSV,避免覆盖且只写一次表头 contracts.to_csv(output, sep="|", mode='a', header=first_chunk, index=False) first_chunk = False
步骤2:安全转换日期(避免中断)
如果不想中途中断,可以用errors='coerce'把无效日期转为NaT,后续过滤掉无效数据:
# 替换日期转换行 contracts[name_date_end] = pd.to_datetime(contracts[name_date_end], dayfirst=True, format='mixed', errors='coerce') # 同时过滤无效日期和未过期合同 contracts = contracts[(contracts[name_date_end] >= date_report) & (contracts[name_date_end].notna())]
步骤3:修复分块写入覆盖问题
必须添加mode='a'参数,并通过first_chunk控制表头只写入一次,否则每次块写入都会覆盖之前的结果。
关键说明
- Pandas的
pd.to_datetime仅支持1677-09-21 00:12:43到2262-04-11 23:47:16范围内的时间戳,超出该范围的日期会触发OutOfBoundsDatetime错误。 - 小样本运行正常是因为刚好没包含脏数据,大文件中存在零散的无效日期格式。
- 分块处理时,每个块的索引是局部的(从0开始),不要混淆全局行号和局部行号。
内容的提问来源于stack exchange,提问作者Malicious Bread Boy
相关产品推荐
相关产品推荐

