Python 提取数据中datetime类型列的月份第一天

Python 提取数据中datetime类型列的月份第一天,python,pandas,dataframe,datetime64,Python,Pandas,Dataframe,Datetime64,我有以下数据帧: user_id purchase_date 1 2015-01-23 14:05:21 2 2015-02-05 05:07:30 3 2015-02-18 17:08:51 4 2015-03-21 17:07:30 5 2015-03-11 18:32:56 6 2015-03-03 11:02:30 而purchase\u date是datetime64[

我有以下数据帧:

user_id    purchase_date 
  1        2015-01-23 14:05:21
  2        2015-02-05 05:07:30
  3        2015-02-18 17:08:51
  4        2015-03-21 17:07:30
  5        2015-03-11 18:32:56
  6        2015-03-03 11:02:30
purchase\u date
datetime64[ns]
列。我需要添加一个新列
df[month]
,其中包含购买日期当月的第一天:

df['month']
2015-01-01
2015-02-01
2015-02-01
2015-03-01
2015-03-01
2015-03-01
我在SQL中寻找类似于
DATE\u格式(购买日期,“%Y-%m-01”)的东西m
。我尝试了以下代码:

     df['month']=df['purchase_date'].apply(lambda x : x.replace(day=1))

它以某种方式工作,但返回:
2015-01-01 14:05:21

最简单、最快的方法是通过转换为
numpy数组,然后进行强制转换:

df['month'] = df['purchase_date'].to_numpy().astype('datetime64[M]')
print (df)
   user_id       purchase_date      month
0        1 2015-01-23 14:05:21 2015-01-01
1        2 2015-02-05 05:07:30 2015-02-01
2        3 2015-02-18 17:08:51 2015-02-01
3        4 2015-03-21 17:07:30 2015-03-01
4        5 2015-03-11 18:32:56 2015-03-01
5        6 2015-03-03 11:02:30 2015-03-01
另一个解决方案是使用和
pd.offsets.MonthBegin(1)
并添加
pd.offsets.MonthEnd(0)
以获得正确的输出,如果月份的第一天:

df['month'] = (df['purchase_date'].dt.floor('d') + 
                           pd.offsets.MonthEnd(0) - pd.offsets.MonthBegin(1))
print (df)
   user_id       purchase_date      month
0        1 2015-01-23 14:05:21 2015-01-01
1        2 2015-02-05 05:07:30 2015-02-01
2        3 2015-02-18 17:08:51 2015-02-01
3        4 2015-03-21 17:07:30 2015-03-01
4        5 2015-03-11 18:32:56 2015-03-01
5        6 2015-03-03 11:02:30 2015-03-01

最后一个解决方案是创建
月周期

。。。然后按
datetimes
by,但速度有点慢:

df['month'] = df['purchase_date'].dt.to_period('M').dt.to_timestamp()
print (df)
   user_id       purchase_date      month
0        1 2015-01-23 14:05:21 2015-01-01
1        2 2015-02-05 05:07:30 2015-02-01
2        3 2015-02-18 17:08:51 2015-02-01
3        4 2015-03-21 17:07:30 2015-03-01
4        5 2015-03-11 18:32:56 2015-03-01
5        6 2015-03-03 11:02:30 2015-03-01
有很多解决方案,因此:

计时(在1.2.3中):

我们可以结合使用:

试试这个

df['month']=pd.to_datetime(df.purchase_date.astype(str).str[0:7]+'-01')

Out[187]: 
   user_id        purchase_date       month
0        1  2015-01-23 14:05:21  2015-01-01
1        2  2015-02-05 05:07:30  2015-02-01
2        3  2015-02-18 17:08:51  2015-02-01
3        4  2015-03-21 17:07:30  2015-03-01
4        5  2015-03-11 18:32:56  2015-03-01
5        6  2015-03-03 11:02:30  2015-03-01

对于我来说,
df['purchase_date']-pd.offset.MonthBegin(1)
不起作用(它在每月的第一天失效),所以我将按如下方式减去每月的天数:

df['purchase_date'] - pd.to_timedelta(df['purchase_date'].dt.day - 1, unit='d')

@Eyal:这就是我使用pd.offsets.MonthBegin来获取月份第一天的方法,并处理当天已经是月份第一天的场景

import datetime

from_date= pd.to_datetime('2018-12-01')

from_date = from_date - pd.offsets.MonthBegin(1, normalize=True) if not from_date.is_month_start else from_date

from_date
df['date'] = df['purchase_date'].apply(lambda x: x.strftime('%Y-%m-01'))

print(df)
 user_id   purchase_date       date
0   1   2015-01-23 14:05:21 2015-01-01
1   2   2015-02-05 05:07:30 2015-02-01
2   3   2015-02-18 17:08:51 2015-02-01
3   4   2015-03-21 17:07:30 2015-03-01
4   5   2015-03-11 18:32:56 2015-03-01
5   6   2015-03-03 11:02:30 2015-03-01
结果:
时间戳('2018-12-01 00:00:00')


结果:
时间戳('2018-12-01 00:00:00')

大多数建议的解决方案在每月的第一天不起作用

以下解决方案适用于每月的任何一天:

df['month']=df['purchase\u date']+pd.offset.MonthEnd(0)-pd.offset.MonthBegin(normalize=True)
[编辑]

另一个更具可读性的解决方案是:

从pandas.tseries.offset导入MonthBegin
df['month']=df['purchase_date'].dt.normalize().map(MonthBegin().rollback)
注意不要使用:

df['month']=df['purchase\u date'].map(MonthBegin(normalize=True).回滚)

由于错误,第一天的结果不正确:

要提取每个月的第一天,您可以编写一个小助手函数,如果提供的日期已经是月的第一天,该函数也可以工作。函数如下所示:

df['purchase_date'] - pd.to_timedelta(df['purchase_date'].dt.day - 1, unit='d')
def第一个月(日期):
返回日期+pd.OFFSET.MonthEnd(-1)+pd.OFFSET.Day(1)
您可以
pd.Series
上应用此功能:

df['month']=df['purchase\u date']。应用(每月的第一个月)
这样,您将得到
列作为
时间戳
。如果需要特定格式,可以使用
strftime()
方法对其进行转换

df['month\u str']=df['month'].dt.strftime(“%Y-%m-%d”)

这个简单的解决方案怎么样?
由于
purchase\u date
已采用
datetime64[ns]
格式,因此您可以使用将日期设置为始终具有月份的第一天

import datetime

from_date= pd.to_datetime('2018-12-01')

from_date = from_date - pd.offsets.MonthBegin(1, normalize=True) if not from_date.is_month_start else from_date

from_date
df['date'] = df['purchase_date'].apply(lambda x: x.strftime('%Y-%m-01'))

print(df)
 user_id   purchase_date       date
0   1   2015-01-23 14:05:21 2015-01-01
1   2   2015-02-05 05:07:30 2015-02-01
2   3   2015-02-18 17:08:51 2015-02-01
3   4   2015-03-21 17:07:30 2015-03-01
4   5   2015-03-11 18:32:56 2015-03-01
5   6   2015-03-03 11:02:30 2015-03-01
因为我们使用了
strftime
,现在
date
列位于
object
(string)类型中:

现在,如果您希望它位于
datetime64[ns]
中,只需使用:


或者将
normalize
作为参数传递,
df.purchase\u date-pd.offset.MonthBegin(1,normalize=True))
@bradsomon,哇!非常感谢。我不知道
pd.offsets.MonthBegin()
有这样一个parameter@MaxU如果
df['purchase\u date']
已经在一个月的第一天,减去
MonthBegin(1)
将返回上个月的第一天。如果购买日期已经是该月的第一天,该怎么办?对于
2017-08-01 03:45:56
我得到:
2017-07-01
pd.offset的问题。MonthBegin(1)
是当购买日期是一个月的第一天时,您的代码将返回上个月的第一天。@pomber-尝试使用
pd.offset.MonthBegin(0)
pd.offset.MonthBegin(0)
适用于第一天,但不适用于REST我同意,当日期为每月第一天时,解决方案是有缺陷的。答案是如何被接受的?它只是有缺陷,它完全忽略了角落案例(每月的第一天或最后一天,取决于
MonthBegin
)@jezrael,请使用
2015-01-01
2015-01-31
扩展您的示例以了解问题。虽然这是在月初一天有效的唯一解决方案,但由于某些原因,它比使用MonthBegin慢得多,您是否能够加快速度?即使在月初一天,这也非常有效。我将其矢量化,而不是像这样执行
.apply()
df['date\u flat']=df['date']+pd.offsets.MonthEnd(-1)+pd.offsets.Day(1)
这也适用于月的最后一天
pd.to\u日期时间('2021-01-31')+pd.tseries.offsets.monthbeng(0)-pd.tseries.offsets.MonthBegin()=时间戳('2021-01-01-01-01 00:00')
import datetime

from_date= pd.to_datetime('2018-12-01')

from_date = from_date - pd.offsets.MonthBegin(1, normalize=True) if not from_date.is_month_start else from_date

from_date
from_date= pd.to_datetime('2018-12-05')

from_date = from_date - pd.offsets.MonthBegin(1, normalize=True) if not rom_date.is_month_start else from_date

from_date
df['date'] = df['purchase_date'].apply(lambda x: x.strftime('%Y-%m-01'))

print(df)
 user_id   purchase_date       date
0   1   2015-01-23 14:05:21 2015-01-01
1   2   2015-02-05 05:07:30 2015-02-01
2   3   2015-02-18 17:08:51 2015-02-01
3   4   2015-03-21 17:07:30 2015-03-01
4   5   2015-03-11 18:32:56 2015-03-01
5   6   2015-03-03 11:02:30 2015-03-01
print(df.dtypes)
user_id                   int64
purchase_date    datetime64[ns]
date                     object
dtype: object
df['date'] = pd.to_datetime(df['date'])

print(df.dtypes)
user_id                   int64
purchase_date    datetime64[ns]
date             datetime64[ns]
dtype: object