Python - Pandas: conversión de fecha a formato utilizable y período de conteo

CorePress2024-01-25  158

Tengo un DataFrame como este:

           timestamp                   
0          09/May/2016:10:53:30  
1          09/May/2016:10:54:30  
2          09/May/2016:10:55:30             
3          09/May/2016:10:56:30
4          09/May/2016:10:57:30
5          09/May/2016:10:58:30
6          09/May/2016:10:59:30  

El formato es día/mes/año:horas:minutos:segundos

Necesito calcular un período de dos minutos para cada marca de tiempo. Pero el problema aquí es que la fecha tiene un formato incorrecto para usarse con la función pandas to_period. Lo he probado:

df['Period'] = pd.to_datetime(df['timestamp']).dt.to_period(minute=2, errors='coerce')

Pero esto genera una excepción:

Unknown string format

El resultado esperado sería como:

           timestamp                         Period
0          09/May/2016:10:53:30                 1
1          09/May/2016:10:54:30                 1
2          09/May/2016:10:55:30                 1                 
3          09/May/2016:10:56:30                 2
4          09/May/2016:10:57:30                 2
5          09/May/2016:10:58:30                 2
6          09/May/2016:10:59:30                 3

Cualquier consejo será muy apreciado.

Puedes pasar el formato de la cadena de fecha y hora mientras llamas a pd.to_datetime y además to_period no parece tener minuel parámetro.

- ThePyGuy

28/03/2021 a las 17:10

Está ahí para Period, no para el método to_period

- ThePyGuy

28/03/2021 a las 17:18

Sí, es un error. ¿Puedo utilizar Period para este propósito?

- Sr. Ingeniero

28/03/2021 a las 17:19

Qué extraño, arroja la misma excepción.

- Sr. Ingeniero

28/03/2021 a las 17:20



------------------------------------

El error proviene del formato de fecha que tienes. Es posible que deba convertir el nombre de su mes a números, p. Mayo --> "05" y especifica el formato:

date_format = "%d/%m/%Y:%H:%M:%S"
dict_months = {
    "January": "01",
    "February": "02",
    "March": "03",
    "April": "04",
    "May": "05",
    "June": "06",
    "July": "07",
    "August": "08",
    "September": "09",
    "October": "10",
    "November": "11",
    "December": "12"
}

Esto hará que el error desaparezca...

Está un poco sucio (y puede que exista una función pandas nativa para hacerlo, ¯_(ツ)_/¯), pero aquí hay una solución:


# define your start date and a period, and then after every period minutes increment the value of period like this
start_date = pd.to_datetime("09/05/2016:10:53:30", format=date_format)
period = 2
time_period_func = lambda x: int(1 + ((x - start_date).total_seconds()//60 ) // (period+1))

df["period"] = pd.to_datetime(df["timestamp"].replace(dict_months, regex=True), format=date_format).apply(time_period_func)

básicamente obtienes el delta de tiempo en minutos entre la fecha actual y el inicio. Luego aplicas una fórmula simple para obtener el período dividiendo el tiempodelta bu período.

Edición 1: Mi respuesta no tuvo en cuenta los segundos, ¡solo los minutos de la marca de tiempo! Si también quieres considerar los segundos, consulta la respuesta de @ThePyGuy, que creo que es el camino correcto a seguir

1

Esto resuelve el primer problema: ¿cómo calcularía el período por frecuencia de dos minutos?

- Sr. Ingeniero

28/03/2021 a las 17:36



------------------------------------

Necesita pasar el formato adecuado al pd.to_datetime

    >>timestamp = pd.to_datetime(df['timestamp'], format='%d/%b/%Y:%H:%M:%S')
    >>timestamp
    0   2016-05-09 10:53:30
    1   2016-05-09 10:54:30
    2   2016-05-09 10:55:30
    3   2016-05-09 10:56:30
    4   2016-05-09 10:57:30
    5   2016-05-09 10:58:30
    6   2016-05-09 10:59:30
    Name: timestamp, dtype: datetime64[ns]

Ahora, puede calcular el tiempo transcurrido desde la primera fila y obtener la diferencia de tiempo en segundos, luego dividirla por 120 (=2 minutos) y finalmente redondearla. Terminarás con algo como

    >>periods=((timestamp - timestamp.iloc[0]).dt.total_seconds()/120).round()
    >>periods
    0    0.0
    1    1.0
    2    1.0
    3    2.0
    4    2.0
    5    2.0
    6    3.0
    Name: timestamp, dtype: float64

Es posible que hayas notado que el primer valor es 0,0, lo cual es obvio, ya que estamos restando el mismo valor para la primera fila, puedes simplemente reemplazar este valor por 1. periodos.iloc[0] = 1

Entonces el resultado final se convierte en:

    >>periods
    0    1.0
    1    1.0
    2    1.0
    3    2.0
    4    2.0
    5    2.0
    6    3.0
    Name: timestamp, dtype: float64

También puedes verificar este método para algunos otros datos.

>>timestamp
0   2016-05-09 10:53:30
1   2016-05-09 10:58:30
2   2016-05-09 10:59:30
3   2016-05-09 11:20:30
4   2016-05-09 11:25:30
5   2016-05-09 11:30:30
6   2016-05-09 11:31:30

periods=((timestamp - timestamp.iloc[0]).dt.total_seconds()/120).round()
periods.iloc[0] = 1

Salida:

>>periods
0     1.0
1     2.0
2     3.0
3    14.0
4    16.0
5    18.0
6    19.0
Name: timestamp, dtype: float64

5

1

bueno. Solo para agregar, tal vez sea mejor usar timestamp.min() en lugar de .iloc porque no hay garantía de que los datos estén ordenados

- Alka

28/03/2021 a las 18:51

sí, o simplemente puedo crear la máscara para periodos=0

-ElPyGuy

28/03/2021 a las 18:52

Lo siento, no estoy seguro de haber sido lo suficientemente claro. Lo que quise decir es que al tomar la diferencia desde la primera fecha, será más seguro hacerlo como timestamp - timestamp.min() en lugar de timestamp - timestamp.iloc[0], como si la serie no estuviera ordenada. iloc[0] realmente no será la primera cita (en el sentido de la más temprana)

- Alka

28/03/2021 a las 19:04

Oh, sí, simplemente asumí los datos que proporcionaste.

- ThePyGuy

28/03/2021 a las 19:16

Estoy bastante seguro de que esta es la forma más sencilla de lograr lo que necesito. ¡Gracias!

- Sr. Ingeniero

29 de marzo de 2021 a las 8:55

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare