使用Pandas合并日期时间列时触发ValueError(hour必须在0..23)的解决方法
问题场景
你有如下结构的DataFrame:
| date | time |
|---|---|
| 2018-01-01 00:00:00 | 7:30:33 |
| 2017-01-01 00:00:00 | 7:30:33 |
想要合并date和time列生成格式为YYYY-MM-DD HH:MM:SS的datetime列,使用了代码:
df["datetime"] = pd.to_datetime(df['date'].apply(str)+' '+df['time'])
大部分情况正常,但偶尔触发ValueError: hour must be in 0..23错误。
问题原因
这个错误的核心是:你的time列中存在无效的小时值——比如出现了24:00:00、25:30这类超出0-23范围的时间,Pandas在解析这类不符合标准时间格式的内容时就会抛出异常。
解决方案
1. 先定位异常数据
第一步要找出那些有问题的时间记录,这样才能针对性处理:
# 拆分时间字符串,提取小时部分并检查是否在0-23范围内 invalid_rows = df[~df['time'].str.split(':').str[0].astype(int).between(0, 23)] print("存在异常时间的行:") print(invalid_rows)
执行后你就能看到哪些行的时间格式有问题,大概率是数据录入错误(比如把凌晨1点写成了25点),或者是12小时制时间没带AM/PM标记(不过这种情况更多是小时超过12但没转换)。
2. 处理异常值并合并列
根据异常数据的类型,选择适合的处理方式:
方式一:跳过无效数据(快速解决)
如果不需要保留那些异常记录,可以用errors='coerce'参数让Pandas把无法解析的时间转为NaT(Not a Time),之后再过滤掉这些无效行:
# 合并日期时间,无法解析的转为NaT df["datetime"] = pd.to_datetime(df['date'].astype(str) + ' ' + df['time'], errors='coerce') # 移除包含无效datetime的行 df = df.dropna(subset=['datetime'])
注:把df['date'].apply(str)换成df['date'].astype(str)性能更好,尤其是处理大数据量时。
方式二:修正异常时间(保留数据)
如果是比如24:00:00这种常见的录入错误(实际应为次日00:00:00),可以手动修正:
# 筛选出小时为24的行 mask = df['time'].str.startswith('24:') # 日期加1天 df.loc[mask, 'date'] = pd.to_datetime(df.loc[mask, 'date']) + pd.Timedelta(days=1) # 把时间改为00:xx:xx df.loc[mask, 'time'] = '00:' + df.loc[mask, 'time'].str[3:] # 再合并列 df["datetime"] = pd.to_datetime(df['date'].astype(str) + ' ' + df['time'])
方式三:指定格式解析(更高效严谨)
如果你的date和time格式是固定的(比如date是YYYY-MM-DD,time是HH:MM:SS),推荐用format参数指定解析格式,这样不仅解析速度更快,还能提前明确格式要求:
df["datetime"] = pd.to_datetime(df['date'].astype(str) + ' ' + df['time'], format='%Y-%m-%d %H:%M:%S')
如果有不符合这个格式的记录,会直接抛出错误,这时候可以结合errors='coerce'来灵活处理。
内容的提问来源于stack exchange,提问作者freddy888

