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