index python pandas dataframe datetime64

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