查找Pandas DataFrame Series月末

96

我有一个DataFrame中的一系列数据,最初我将其读入为对象,现在需要将其转换为日期形式,格式为yyyy-mm-dd,其中dd是月末。

例如,我有一个名为df的DataFrame,其中包含一个对象类型的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(pd)和datetime(dt)。

3个回答

179
你可以使用pandas.tseries.offsets.MonthEnd:
from pandas.tseries.offsets import MonthEnd

df['Date'] = pd.to_datetime(df['Date'], format="%Y%m") + MonthEnd(0)
MonthEnd中的0只是指定将日期向前滚动到给定月份的末尾。请注意,如果我们使用了MonthEnd(1),那么我们将得到下一个日期,即该月底部的日期。 如果要获取下个月的最后一天,则需要再添加一个额外的MonthEnd(1),以此类推。这对于任何月份都适用,因此您不需要知道月份中的天数或其他任何信息。更多偏移信息可以在文档中找到。
示例用法和输出:
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

1
这绝对是我见过的最优雅的解决方案之一,谢谢! :) - Lisle
2
没问题!MonthEnd是Pandas中隐藏的宝石之一,你可能不会立即想到Pandas会有这个功能。通常我的第一反应是使用其他日期时间库...直到我记起Pandas有这么酷的功能! - root
8
你应该查看@martien lubberink的回答,了解上述内容的一些警告。 - evan54
1
这似乎不适用于pandas 0.19.2和numpy 1.13.1。收到错误消息 "数据类型datetime未被理解"。有人遇到过这个问题吗? - iwbabn
9
正如Martein的回答所解释的那样,使用MonthEnd(1)来获取月份的最后一天是不正确的,应该始终使用MonthEnd(0) - Asclepius
1
有人可以请编辑一下答案吗?如上所述,我们应该使用MonthEnd(0)而不是MonthEnd(1)。这个问题非常常见,最高评分的答案错误会误导人们。 - Moysey Abramowitz

95

同意使用root offers的方法。然而,盲目使用 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'

1
月底可以是该月的最后一天/分钟/秒/毫秒/微秒/纳秒,具体取决于您的使用情况所需的偏移量。给定一个日期,要推导出该月的最后一个单位,需要使用适用的锚定偏移语义。例如:
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)的观察结果归功于Martien的回答

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接