Python如何提取日期列中的年和月_通过dt访问器获取year与month属性
Python如何提取日期列中的年和月?通过dt访问器获取year与month属性

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
为什么直接用 df['date'].year 会报 AttributeError?
很多朋友在提取日期信息时,会下意识地直接调用 df['date'].year,结果迎面就是一个 AttributeError。问题出在哪?其实,Series 对象本身并没有 year 这个属性。只有那些已经被明确转换为 datetime64 类型的 Series,才能通过专门的 .dt 访问器来获取年、月、日等时间属性。如果你的日期列还是字符串或者 object 类型,直接调用 .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'])。默认情况下,pandas 会尽力解析,遇到实在看不懂的值,会设为NaT(Not a Time)。 - 处理异常:如果数据里混着像
"2023-13-01"这种不合法的日期,建议加上参数errors='coerce',让 pandas 安静地把它们变成NaT,而不是直接报错中断整个流程。
如何安全提取 year 和 month 并避免 NaN 引发的类型问题?
成功转换后,用 .dt.year 和 .dt.month 提取似乎很简单,但这里有个暗坑:它们返回的是 Int64 类型,这是一种支持 NaN 的整数类型。当你兴冲冲地想把结果拿去拼接字符串或做计算时,NaN 可能会带来意想不到的兼容性问题。尤其要注意,.dt.month 对于正常日期返回 1 到 12,但对于 NaT,它返回的是 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,转成字符串就成了"nan",结果会变成“2023-nan”。有更优雅的方法:df['date'].dt.to_period('M').astype(str)。
dt.to_period('M') 比手动拼 year/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')比用两个独立的整数列更简洁,语义也更清晰。 - 注意限制:当然,
Period类型不能直接进行数学运算。如果你需要计算月份差,得先转回时间戳:(p2.to_timestamp() - p1.to_timestamp()) / np.timedelta64(1, 'M')。
从字符串列提取年月时,format 参数能提升性能吗?
不仅能,而且提升非常明显。当你的日期字符串格式统一且已知时(比如全是 "%Y/%m/%d"),在调用 pd.to_datetime() 时传入 format 参数,pandas 就可以跳过耗时的格式自动推断过程。对于百万行级别的数据,这个操作带来的速度提升可能达到 5 到 10 倍。
性能优化的实操建议如下:
立即学习“Python免费学习笔记(深入)”;
- 确认格式:确保格式统一后,使用
pd.to_datetime(df['date'], format='%Y-%m-%d')。 - 错误处理:指定格式后,一旦遇到不匹配的字符串,pandas 会直接报
ValueError。初次尝试时,建议加上errors='coerce'来探查数据质量,看看有多少行无法解析。 - 常见格式符号:记住几个常用的:
%Y(四位年份)、%y(两位年份)、%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() 快速检查一下有没有隐藏字符。磨刀不误砍柴工,这一步探查能省去后面大量的调试时间。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
ThinkPHP事务锁表怎么解_ThinkPHP死锁排查与优化【教程】
ThinkPHP事务锁表怎么解?死锁排查与优化实战指南 先说一个核心判断:你在ThinkPHP事务中遇到的锁表或死锁问题,本质上并非框架缺陷,而是数据库底层机制、事务执行顺序与引擎配置共同作用的结果。动手改代码之前,务必先确认三件事:表引擎是不是MyISAM?是否存在未提交的长事务?是否在非更新场景
ThinkPHP多语言小程序怎么接_ThinkPHP多语言微信端解答【技巧】
ThinkPHP多语言在微信小程序中的手动控制策略 想在微信小程序里用上ThinkPHP的多语言功能?没问题,但得换换思路。它和传统的Web端有个根本区别:语言切换必须手动控制,没法依赖浏览器的自动检测机制。原因很简单,小程序环境里既没有HTTP_ACCEPT_LANGUAGE请求头,也不会自动走C
python及pycharm的安装与环境配置的过程(附详细图文)
前言 对于嵌入式、机器人开发来说,Python 往往是绕不开的核心工具。而一切学习的起点,都始于一个稳定、可靠的开发环境。今天,我们就来手把手地走一遍 Python 解释器和 PyCharm IDE 的安装全流程。从官网下载、环境配置到最终验证,每一步都配有清晰的图文说明,目标就是帮你快速、无痛地搭
SpringBoot+Disruptor实现特快高并发处理
01、背景 最近在项目里用到了Disruptor做消息队列——没错,你没看错,不是Kafka,也不是RabbitMQ。Disruptor最大的一个特点,就是快。当然,它还是开源的。这篇文章,就带你快速认识一下它,并记录一个基础的入门示例。 02、Disruptor 介绍 先来聊聊Disruptor的
mybatis动态SQL常用的标签使用及说明
1 标签 在MyBatis的动态SQL世界里,标签有个更接地气的名字——SQL片段。它的作用,说白了就是帮你把一段常用的SQL语句“打包”起来,方便在多个地方重复调用。 怎么用呢?很简单。你只需要给这个片段起一个在当前命名空间下独一无二的ID,然后在需要的地方,用标签通过这个ID把它“引入”进来就
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

