python - index - Extraer el primer día del mes de una columna de tipo datetime en pandas
object to datetime pandas (5)
@Eyal: Esto es lo que hice para obtener el primer día del mes usando pd.offsets.MonthBegin
y manejar el escenario donde el día ya es el primer día del mes.
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
resultado: Timestamp(''2018-12-01 00:00:00'')
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
resultado: Timestamp(''2018-12-01 00:00:00'')
Tengo el siguiente marco de datos:
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
y purchase_date
es una columna datetime64[ns]
. Necesito agregar una nueva columna df[month]
que contenga el primer día del mes de la fecha de compra:
df[''month'']
2015-01-01
2015-02-01
2015-02-01
2015-03-01
2015-03-01
2015-03-01
Estoy buscando algo como DATE_FORMAT(purchase_date, "%Y-%m-01") m
en SQL. He intentado el siguiente código:
df[''month'']=df[''purchase_date''].apply(lambda x : x.replace(day=1))
Funciona de alguna manera pero regresa: 2015-01-01 14:05:21
.
Más simple y rápido se convierte a numpy array
por values
y luego se convierte:
df[''month''] = df[''purchase_date''].values.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
Otra solución con floor
y pd.offsets.MonthBegin(0)
:
df[''month''] = df[''purchase_date''].dt.floor(''d'') - 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
df[''month''] = (df[''purchase_date''] - pd.offsets.MonthBegin(1)).dt.floor(''d'')
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
La última solución es crear un month period
por to_period
:
df[''month''] = df[''purchase_date''].dt.to_period(''M'')
print (df)
user_id purchase_date month
0 1 2015-01-23 14:05:21 2015-01
1 2 2015-02-05 05:07:30 2015-02
2 3 2015-02-18 17:08:51 2015-02
3 4 2015-03-21 17:07:30 2015-03
4 5 2015-03-11 18:32:56 2015-03
5 6 2015-03-03 11:02:30 2015-03
... y luego a los to_timestamp
datetimes
por to_timestamp
, pero es un poco más lento:
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
Hay muchas soluciones, así que:
Tiempos :
rng = pd.date_range(''1980-04-03 15:41:12'', periods=100000, freq=''20H'')
df = pd.DataFrame({''purchase_date'': rng})
print (df.head())
In [300]: %timeit df[''month1''] = df[''purchase_date''].values.astype(''datetime64[M]'')
100 loops, best of 3: 9.2 ms per loop
In [301]: %timeit df[''month2''] = df[''purchase_date''].dt.floor(''d'') - pd.offsets.MonthBegin(1)
100 loops, best of 3: 15.9 ms per loop
In [302]: %timeit df[''month3''] = (df[''purchase_date''] - pd.offsets.MonthBegin(1)).dt.floor(''d'')
100 loops, best of 3: 12.8 ms per loop
In [303]: %timeit df[''month4''] = df[''purchase_date''].dt.to_period(''M'').dt.to_timestamp()
1 loop, best of 3: 399 ms per loop
#MaxU solution
In [304]: %timeit df[''month5''] = df[''purchase_date''].dt.normalize() - pd.offsets.MonthBegin(1)
10 loops, best of 3: 24.9 ms per loop
#MaxU solution 2
In [305]: %timeit df[''month''] = df[''purchase_date''] - pd.offsets.MonthBegin(1, normalize=True)
10 loops, best of 3: 28.9 ms per loop
#Wen solution
In [306]: %timeit df[''month6'']= pd.to_datetime(df.purchase_date.astype(str).str[0:7]+''-01'')
1 loop, best of 3: 214 ms per loop
Para mí df[''purchase_date''] - pd.offsets.MonthBegin(1)
no funcionó (falla el primer día del mes), así que estoy restando los días del mes como este:
df[''purchase_date''] - pd.to_timedelta(df[''purchase_date''].dt.day - 1, unit=''d'')
Podemos usar el desplazamiento de fecha junto con Series.dt.normalize :
In [60]: df[''month''] = df[''purchase_date''].dt.normalize() - pd.offsets.MonthBegin(1)
In [61]: df
Out[61]:
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
O una solución mucho mejor de @BradSolomon
In [95]: df[''month''] = df[''purchase_date''] - pd.offsets.MonthBegin(1, normalize=True)
In [96]: df
Out[96]:
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
Prueba esto ..
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