如何将日期设置为该月的第一个日期?

Posted

技术标签:

【中文标题】如何将日期设置为该月的第一个日期?【英文标题】:How to floor a date to the first date of that month? 【发布时间】:2017-07-06 05:22:51 【问题描述】:

我有一个索引列 = date 的 pandas DataFrame。

输入:

            value
date    
1986-01-31  22.93
1986-02-28  15.46

我想把日期推迟到那个月的第一天

输出:

            value
date    
1986-01-01  22.93
1986-02-01  15.46

我尝试了什么:

df.index.floor('M')
ValueError: <MonthEnd> is a non-fixed frequency

这可能是因为 df 是由 df = df.resample("M").sum()(这段代码的输出就是问题开头的输入)

我也试过df = df.resample("M", convention='start').sum()。但是,它不起作用。

我知道在 R 中,很容易调用 floor(date, 'M')

【问题讨论】:

性能有问题吗?为此,我会考虑将这些值转换为 datetime 对象,但如果您尝试处理数百万个对象,这可能会很昂贵。 【参考方案1】:

您可以使用时间序列偏移 MonthBegin

from pandas.tseries.offsets import MonthBegin
df['date'] = pd.to_datetime(df['date']) - MonthBegin(1)

编辑: 上述解决方案不处理已经确定到月初的日期。这是一个替代解决方案。

这是一个带有额外测试用例的数据框:

            value
date    
1986-01-31  22.93
1986-02-28  15.46
2018-01-01  20.00
2018-02-02  25.00

使用timedelta方法,

df.index = pd.to_datetime(df.index)
df.index = df.index - pd.to_timedelta(df.index.day - 1, unit='d')


            value
date    
1986-01-01  22.93
1986-02-01  15.46
2018-01-01  20.00
2018-02-01  25.00

【讨论】:

这是所有答案中唯一的 pandonic 方法(作为奖励,这是矢量化的) 这种方法有一个错误:它将任何日期转换为下个月的月初,除了月初,它保持不变。即 1-1-2018 -> 1-1-2018,但 2-1-2018 -> 1-2-2018... timedelta 方法是正确的,非常适合我的用例,只需进行一项修改 - 添加“dt”,因此在 to_timedelta() 中更改为“df.index.dt.day” .【参考方案2】:
dt_1 = "2016-02-01"
def first_day(dt):
    lt_split = dt.split("-")
    return "-".join([lt_split[0], lt_split[1], "01"])

print first_day(dt_1)

对于 Panda 的 DataFrame,可以使用dt["col_name_date"].apply(first_day)

【讨论】:

【参考方案3】:

这样就可以解决问题,并且不需要导入。 Numpy 有一个 dtype datetime64,默认情况下 pandas 设置为 [ns],通过检查 dtype 可以看出。您可以将其更改为月份,这将通过访问 numpy 数组并更改类型从每月的第一天开始。

df.date = pd.to_datetime(df.date.values.astype('datetime64[M]'))

如果 pandas 能用他们自己的 astype() 方法来实现它会很好,但不幸的是你不能。

以上适用于日期时间值或字符串的数据,如果您已经将数据设置为 datetime[ns] 类型,则可以省略 pd.to_datetime() 并执行以下操作:

df.date = df.date.values.astype('datetime64[M]')

【讨论】:

我不知道他们在哪个版本中将它导入到 pandas astype,但目前 df.date.astype('datetime64[M]') 有效(至少 1.2.2 版)。你可以更新这个答案。【参考方案4】:

这是另一种“流行”的做法:

df.date - pd.Timedelta('1 day') * (df.date.dt.day - 1)

【讨论】:

这很好!另外,它适用于 dask! (与 Deo Leung 的回答相反) 除了向量化之外,这也适用于时间戳的可变实例。只需使用您的时间戳更改 df.date 即可,效果很好!【参考方案5】:

有一个pandas issue关于地板问题

建议的方式是

import pandas as pd
pd.to_datetime(df.date).dt.to_period('M').dt.to_timestamp()

【讨论】:

df.date.dt.to_period('M').dt.to_timestamp() 似乎足够了,不需要初始的pd.to_datetime【参考方案6】:

您也可以使用字符串日期时间格式:

df['month'] = df['date'].dt.strftime('%Y-%m-01')

【讨论】:

【参考方案7】:

从 2019 年 8 月开始:

这应该可行:

[x.replace(day=1).date() for x in df['date']]

唯一的要求是确保date 是一个日期时间,我们可以通过调用pd.to_datetime(df['date']) 来保证这一点

【讨论】:

【参考方案8】:

喜欢 Mikhail Venkov 的回答。添加了下面的代码以将列添加为时间戳值并保留时区信息

    df['month'] = pd.to_datetime(df['timestamp'].dt.strftime('%Y-%m-01')).dt.tz_localize(timezone) 

where timezone = 'America/Los_Angeles' 或您想要的任何区域

【讨论】:

【参考方案9】:

假设您正在处理以下数据框:

import pandas as pd

df = pd.DataFrame('MyDate': ['2021-03-11', '2021-04-26', '2021-01-17'])
df['MyDate'] = pd.to_datetime(df.MyDate)

这是:

    MyDate
0   2021-03-11
1   2021-04-26
2   2021-01-17

并且您想将日期截断为月份:

df['Truncated'] = df['MyDate'] + pd.offsets.MonthBegin(-1)
# OR    
# df['Truncated'] = df['MyDate'] - pd.offsets.MonthBegin(1)
df

你会得到:

      MyDate  Truncated
0 2021-03-11 2021-03-01
1 2021-04-26 2021-04-01
2 2021-01-17 2021-01-01

重要提示:当日期已经确定为当月的第一天时,此方法不起作用,因此我们还将提供其他解决方案。

import pandas as pd

df = pd.DataFrame('MyDate': ['2021-03-11', '2021-04-26', '2021-01-17', '2021-02-01'])
df['MyDate'] = pd.to_datetime(df.MyDate)

df['Truncated'] = df['MyDate'].dt.to_period('M').dt.to_timestamp()
print(df)

你会得到:

 MyDate  Truncated
0 2021-03-11 2021-03-01
1 2021-04-26 2021-04-01
2 2021-01-17 2021-01-01

最后,另一种方法可能如下:

df['Truncated'] = df['MyDate'].dt.strftime('%Y-%m-01')
print(df)

你会得到:

    MyDate   Truncated
0 2021-03-11  2021-03-01
1 2021-04-26  2021-04-01
2 2021-01-17  2021-01-01

【讨论】:

如果日期是当月的第一天,您的代码将不起作用 - 它会变成上个月的第一天

以上是关于如何将日期设置为该月的第一个日期?的主要内容,如果未能解决你的问题,请参考以下文章

如何在目标c中获得该月的第n个星期日日期?

在R [重复]中将日期更改为该月的第一天

SQL Server 2005获取任何年份中任何月份的第一个和最后一个日期

将 Epoch 时间转换为日期

如何在Bash脚本中获取上个月的第一个和最后一个日期?

VBA如何判断一个日期是啥星期