Pandas读取CSV日期列解析错误致数据匹配异常排查
碰到这种inner join后日期匹配出错、数据缺失或值不对的问题,我一般会从这几个核心方向排查——都是日常处理时间序列数据时踩过的坑:
1. 日期解析与格式不统一(最常见的坑)
你的源文件日期是DD-MM-YYYY格式,但如果读取时没指定解析规则,或者生成日期范围时用了默认的YYYY-MM-DD逻辑,很容易出现日期被反向解析的情况:
比如源文件里的01-11-2017(11月1日)可能被错误解析成2017-01-11(1月11日),这就会导致:
- 你要找的
2017-11-01匹配到了1月11日的81.00数据,而非正确的124.35 - 像
2017-11-02这类日期,因为解析后根本不存在于原始数据里,inner join直接过滤掉了
验证步骤:
先打印两边的日期值,对比是否一致:
import pandas as pd # 读取数据后打印日期列 df = pd.read_csv('input.csv', header=None) print("原始读取的日期字符串:", df[0].head()) # 打印生成的日期范围 print("目标日期范围:", pd.date_range(start='2017-11-01', end='2017-11-03'))
修复方法:
读取CSV时强制指定日期格式,确保解析正确:
df = pd.read_csv('input.csv', header=None, parse_dates=[0], date_parser=lambda x: pd.to_datetime(x, format='%d-%m-%Y')) # 给列命名(按实际列数调整) df.columns = ['date', 'g1_c']
2. 原始数据的重复日期或脏数据
如果input.csv里同一个日期存在多行数据,inner join时可能会随机匹配到错误的行(比如2017-11-01有两行,一行是124.35,一行是81.00);另外如果原始日期有格式不统一(比如部分是DD/MM/YYYY、部分带空格),也会导致解析失败,日期丢失。
验证步骤:
- 检查重复日期:
# 统计每个日期的出现次数 print(df['date'].value_counts()) # 查看2017-11-01的所有数据 print(df[df['date'] == pd.to_datetime('2017-11-01')])
- 检查解析失败的脏数据:
# 读取原始日期字符串,排查解析错误的行 raw_dates = pd.read_csv('input.csv', header=None)[0] # 尝试解析,找出无法识别的日期 bad_dates = raw_dates[pd.to_datetime(raw_dates, format='%d-%m-%Y', errors='coerce').isna()] print("解析失败的日期:", bad_dates.tolist())
修复方法:
- 去重重复日期(保留正确的那行,比如取最大值/最新行):
# 保留每个日期的g1_c最大值 df = df.groupby('date')['g1_c'].max().reset_index() # 或者保留第一行有效数据 df = df.drop_duplicates(subset='date', keep='first')
- 清洗脏日期:
# 统一分隔符、去掉空格 raw_dates = raw_dates.str.replace('/', '-').str.strip() df['date'] = pd.to_datetime(raw_dates, format='%d-%m-%Y')
3. 数据类型不一致导致隐性不匹配
有时候看起来日期格式一样,但一边是datetime64类型,一边是字符串类型,inner join时会因为类型不匹配无法正确关联。比如生成的日期范围是datetime对象,而读取的date列是字符串,即使格式完全一致,也会匹配失败。
验证步骤:
查看两列的数据类型:
print("原始数据日期类型:", df['date'].dtype) date_range = pd.date_range(start='2017-11-01', end='2017-11-03') print("生成的日期范围类型:", date_range.dtype)
修复方法:
统一转换为datetime类型:
# 确保原始数据日期是datetime类型 df['date'] = pd.to_datetime(df['date'], format='%d-%m-%Y') # 生成日期范围时直接用datetime序列 date_df = pd.DataFrame({'date': pd.date_range(start='2017-11-01', end='2017-11-03')}) # 再执行inner join result = pd.merge(date_df, df, on='date', how='inner')
4. Inner Join的逻辑本身限制
Inner Join只会保留两边都存在的日期,如果2017-11-02、03这些日期在input.csv里本身就没有数据,那join后自然不会出现。如果确定原始数据有这些日期,那还是回到前面的日期解析问题排查。
先从日期解析的正确性入手,这是这类问题90%以上的原因,排查清楚后再处理数据本身的问题。
内容的提问来源于stack exchange,提问作者codenut

