直接用 df['date'].year 报 AttributeError 是因为只有 datetime64 类型的 Series 才能通过 .dt 访问器获取 year 等时间属性;字符串或 object 类型需先用 pd.to_datetime() 转换,推荐加 errors='coerce' 处理异常值。

为什么直接用 df['date'].year 会报 AttributeError?
因为 Series 对象本身没有 year 属性,只有 datetime64 类型的 Series 才能通过 .dt 访问器获取时间属性。如果列是字符串或 object 类型,必须先转成 datetime 类型,否则调用 .dt.year 会抛出 AttributeError: Can only use .dt accessor with datetimelike values。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 先确认列类型:
df['date'].dtype,不是datetime64[ns]就不能直接用.dt - 强制转换再提取:
df['date'] = pd.to_datetime(df['date']),遇到无法解析的值默认设为NaT - 若原始数据含异常格式(如
"2023-13-01"),加参数errors='coerce'避免中断
如何安全提取 year 和 month 并避免 NaN 引发的类型问题?
.dt.year 和 .dt.month 返回的是 Int64(支持 NaN 的整数类型),但下游操作(比如拼接字符串、参与数值计算)可能不兼容 NaN。尤其 .dt.month 返回 1–12,而 NaT 对应的 .dt.month 是 NaN,不是 0。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 提取后检查缺失:
df['date'].dt.year.isna().sum() - 需要填充时用
.fillna(0).astype(int),但注意:月份填 0 不符合业务逻辑,更推荐保留NaN或过滤掉异常行 - 若要生成“年-月”字符串(如
"2023-05"),别用df['date'].dt.year.astype(str) + '-' + df['date'].dt.month.astype(str)—— 因为NaN转 str 会变成"nan";改用df['date'].dt.to_period('M').astype(str)
dt.to_period('M') 比手动拼 year/month 更可靠吗?
是的。手动拼接 year 和 month 容易在边界情况出错:比如 month 是单数字时没补零("2023-5" 而非 "2023-05"),或者遇到 NaT 导致字符串污染。而 .dt.to_period('M') 返回 PeriodIndex,天然归一化、不可变、支持向量化运算,且 NaT 自动转为 NaT(不是字符串)。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 生成年月标识优先用:
df['ym'] = df['date'].dt.to_period('M') - 需要转字符串显示时再调用
.astype(str),结果恒为"YYYY-MM"格式 - 后续做分组统计(如按年月聚合)时,直接用
df.groupby('ym')比用两个 int 列更简洁、语义更清晰 - 注意:
Period类型不能直接用于数学运算,如需计算月份差,得转回 timestamp:(p2.to_timestamp() - p1.to_timestamp()) / np.timedelta64(1, 'M')
从字符串列提取年月时,format 参数能提升性能吗?
能,而且提升显著。当明确知道日期格式(如 "%Y/%m/%d"),传入 format 可跳过 pandas 的自动推断逻辑,速度可快 5–10 倍,尤其对百万级数据。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 确认格式统一后再用:
pd.to_datetime(df['date'], format='%Y-%m-%d') - 格式错误会直接报
ValueError,所以首次使用建议加errors='coerce'探查数据质量 - 常见格式符号:
%Y(4位年)、%y(2位年)、%m(01–12)、%B(英文全称)、%b(缩写) - 如果格式混杂(如部分是
"2023-05-01",部分是"05/01/2023"),别硬凑format,老实用默认解析 +errors='coerce'
实际中真正容易被忽略的,是原始列里藏了空格、隐藏字符或混合类型(比如多数是字符串,夹杂几个浮点数时间戳),这些不会立刻报错,但会让 .dt.year 返回全 NaN 或静默截断。动手前务必用 df['date'].head(10).apply(type) 和 df['date'].str.strip().head() 快速探查。


















