You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pandas to_datetime解析%M:%S.%f时间报错及seaborn绘图异常问题

问题根因
  • 触发ValueError的直接原因:你的时间字符串存在隐藏前导空格(报错信息里的待匹配值为' 7:42.3',数字7前多了1个空格),和你写的%M:%S.%f格式规则不匹配;另外pd.to_datetime本身是用来解析具体日期时间点的,会默认补全年月日信息,并不适配你这种只有分、秒、毫秒的完赛时长类数据。
  • 触发seaborn绘图TypeError的原因:你的时间列始终是object(字符串/混合类型),没有转成seaborn可识别的数值类型,当你把分类类型的运动员姓名放到坐标轴上时,另一轴的非数值数据无法被识别计算,就会抛出变量非数值的错误。
解决步骤

你有多列同格式的时间数据,可以用统一函数批量处理,全程不用逐列手写转换逻辑:

  1. 先写通用转换逻辑,把分秒毫秒格式的时长转成总秒数(纯浮点数值,兼容所有排序、计算、绘图场景,对新手最友好,不会出类型兼容问题)
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter

# 把所有同格式的时间列名放到这个列表里,多列直接逗号分隔追加即可
time_columns = ["CRS1"]

# 时长转换函数:自动处理前后空格、空值,输出数值类型的总秒数
def time_str_to_seconds(time_val):
    # 空值直接返回保留
    if pd.isna(time_val):
        return pd.NA
    # 去掉字符串前后所有隐藏空格,解决前导空格导致的格式匹配失败问题
    clean_str = str(time_val).strip()
    # 拆分分、秒、毫秒部分
    minute_part, sec_ms_part = clean_str.split(":")
    sec_part, ms_part = sec_ms_part.split(".")
    # 累加计算总秒数:你的毫秒是1位,对应0.1秒精度
    total_seconds = int(minute_part) * 60 + int(sec_part) + int(ms_part)/10
    return total_seconds

# 批量转换所有时间列
for col in time_columns:
    df[col] = df[col].apply(time_str_to_seconds)

转换完成后你可以执行print(df["CRS1"].dtype)验证,列类型会变成float,空值保留为NaN,前几行值会是462.3、471.9这类数值,完全符合数值类绘图要求

  1. 直接绘图即可,不会再触发类型错误,示例代码:
plt.figure(figsize=(10, 6))
# 替换成你自己表中运动员姓名对应的列名即可
sns.barplot(data=df, x="CRS1", y="athlete_name")
plt.xlabel("完赛时间")
plt.ylabel("运动员姓名")
plt.show()
  1. (可选)如果想让坐标轴显示回分:秒.毫秒的易读格式,不需要修改原始数据,只要加个刻度格式化函数就行:
# 把数值秒数转回分秒格式用于坐标轴显示
def sec_to_time_str(x, pos):
    mins = int(x // 60)
    secs = x % 60
    return f"{mins}:{secs:.1f}"

# 给x轴应用格式化规则
plt.gca().xaxis.set_major_formatter(FuncFormatter(sec_to_time_str))

不要把时间数据再转回字符串类型做坐标轴,否则会再次触发seaborn的非数值类型报错,格式化显示只需要修改刻度渲染规则即可,原始数据保持数值类型是最稳妥的方案。

内容的提问来源于stack exchange,提问作者Hansson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 20:24:27