查找 Pandas DataFrame 系列的月底

Posted

技术标签:

【中文标题】查找 Pandas DataFrame 系列的月底【英文标题】:Find the end of the month of a Pandas DataFrame Series 【发布时间】:2016-09-18 03:45:43 【问题描述】:

我在 DataFrame 中有一个系列,最初作为对象读取,然后需要将其转换为 yyyy-mm-dd 形式的日期,其中 dd 是月末​​。

例如,我有 DataFrame df,其中包含 Date 列作为对象:

...      Date    ...
...     200104   ...
...     200508   ...

说到这里,我想要的是一个日期对象:

...      Date    ...
...  2001-04-30  ...
...  2005-08-31  ...

这样 df['Date'].item() 返回

datetime.date(2001, 04, 30)

我使用以下代码几乎可以到达那里,但我所有的日期都是在月初,而不是月底。请指教。

df['Date'] = pd.to_datetime(df['Date'], format="%Y%m").dt.date

注意:我已经将 Pandas ad pd 和 datetime 导入为 dt

【问题讨论】:

【参考方案1】:

你可以使用pandas.tseries.offsets.MonthEnd:

from pandas.tseries.offsets import MonthEnd

df['Date'] = pd.to_datetime(df['Date'], format="%Y%m") + MonthEnd(1)

MonthEnd 中的 1 只是指定向前移动一步到下一个月末日期。 (使用0 或将其留空也适用于您的情况)。如果您想要下个月的最后一天,您可以使用MonthEnd(2) 等。这应该适用于任何月份,因此您不需要知道该月的天数或类似的东西。更多偏移信息可以在documentation找到。

示例用法和输出:

df = pd.DataFrame('Date': [200104, 200508, 201002, 201602, 199912, 200611])
df['EndOfMonth'] = pd.to_datetime(df['Date'], format="%Y%m") + MonthEnd(1)

     Date EndOfMonth
0  200104 2001-04-30
1  200508 2005-08-31
2  201002 2010-02-28
3  201602 2016-02-29
4  199912 1999-12-31
5  200611 2006-11-30

【讨论】:

这是迄今为止我见过的最优雅的解决方案之一,谢谢! :) 没问题! MonthEnd 是隐藏在 Pandas 中的宝石之一,您不会立即认为 Pandas 会拥有。通常我的第一直觉是使用其他日期时间库..直到我记得 Pandas 有这么酷的功能! 您应该查看@martien lubberink 的回答,了解上述一些注意事项。 这似乎不适用于 pandas 0.19.2 和 numpy 1.13.1。收到错误“数据类型日期时间不理解”。有人遇到过这个问题吗? 如answer by Martein 中所述,对于一个月的最后一个日期,MonthEnd(1) 的使用是不正确的,而应始终只使用MonthEnd(0)【参考方案2】:

同意 root 提供是正确的方法。然而,盲目使用MonthEnd(1) 的读者如果使用当月的最后一个日期作为输入,他们会大吃一惊:

In [4]: pd.Timestamp('2014-01-01') + MonthEnd(1)
Out[4]: Timestamp('2014-01-31 00:00:00')

In [5]: pd.Timestamp('2014-01-31') + MonthEnd(1)
Out[5]: Timestamp('2014-02-28 00:00:00')

使用MonthEnd(0) 会给出这样的结果:

In [7]: pd.Timestamp('2014-01-01') + MonthEnd(0)
Out[7]: Timestamp('2014-01-31 00:00:00')

In [8]: pd.Timestamp('2014-01-31') + MonthEnd(0)
Out[8]: Timestamp('2014-01-31 00:00:00')

以字符串形式获取月末的示例:

from pandas.tseries.offsets import MonthEnd
(pd.Timestamp.now() + MonthEnd(0)).strftime('%Y-%m-%dT00:00:00')
# '2014-01-31T00:00:00'

【讨论】:

【参考方案3】:

月末可以是该月的最后一天/分钟/秒/毫秒/微秒/纳秒,具体取决于您的用例所需的offset。给定日期,要导出月份的最后一个单位,请使用适用的anchored offset semantics。例如:

import pandas as pd

def last_second_of_month(date: str) -> str:
    return str(pd.Timestamp(date) + pd.offsets.MonthBegin() - pd.offsets.Second())

根据需要,将上面的Second() 替换为Day()Minute()Milli()Micro()Nano()

这是一个具有相同结果的替代实现:

import pandas as pd

def last_second_of_month(date: str) -> str:
    return str((pd.Timestamp(date) + pd.offsets.MonthEnd(0)).date()) + " 23:59:59"

例子:

>>> last_second_of_month('2020-10')
'2020-10-31 23:59:59'
>>> last_second_of_month('2020-10-01')
'2020-10-31 23:59:59'
>>> last_second_of_month('2020-10-15')
'2020-10-31 23:59:59'
>>> last_second_of_month('2020-10-30')
'2020-10-31 23:59:59'
>>> last_second_of_month('2020-10-31')
'2020-10-31 23:59:59'

作为警告,请勿使用 pd.Timestamp(date) + pd.offsets.MonthEnd() + pd.offsets.Day() - pd.offsets.Second(),因为它在一个月的最后一天无法正常工作。关于pd.offsets.MonthEnd(1) 的这一观察归功于answer by Martien。

【讨论】:

以上是关于查找 Pandas DataFrame 系列的月底的主要内容,如果未能解决你的问题,请参考以下文章

pandas使用pd.offsets.MonthEnd把dataframe数据中的时间数据列统一移动到所在月份的月底最后一天(move to month end)

pandas使用pd.offsets.BMonthEnd把dataframe数据中的时间数据列统一移动到所在月份上的月底最后一天(正确获取月末业务商业日期)

pandas使用pd.offsets.MonthEnd把dataframe数据中的时间数据列统一移动到所在月份上的月底最后一天(last day of month)

pandas使用pd.offsets.MonthEnd把dataframe数据中的时间数据列统一移动到所在月份上一个月份的月底最后一天(move to last month end)

pandas使用pd.offsets.MonthEnd把dataframe数据中的时间数据列统一移动到所在月份上一个月份的月底最后一天(move to last month end)

Pandas:查找不在另一个DataFrame中的DataFrame行[重复]