Python: manera eficiente de calcular el promedio móvil para la ventana de tiempo fijo (NOT widnow de observación fija)

Descripción del problema

Di que tengo:

  1. vector de time, el dtipo es numposo datetime64,
  2. vector de parameters, el dtipo es numposo float
  3. tiempo horizon, el dtipo es numposo timedelta64

Y time.shape == parameters.shape. Valores de time son únicos y las distancias entre elementos no son ni siquiera.

Objetivo Tengo: por cada momento t de tiempo calcula algunas estadísticas (por ejemplo, media, min, max, sum, etc.) para el vector de parámetros durante el período de tiempo desde time[t-horizon] a time[t]

La manera novata sería usar un bucle (No quiero usar un bucle por razones de rendimiento) o algunos pandas aggregation/resampling ( sin embargo esto no es ideal como no quiero agregar - esto crea un nuevo vector de tiempo, mientras que quiero preservar mi time.

Mi enfoque actual

Yo creo la siguiente matriz. La visualización de la matriz se establece en datos reales y muestra por qué necesito diferentes rangos para calcular estadísticamente para cada observación por separado - a veces 15min de la historia tiene 5.000 observaciones mientras que a veces aproximadamente pocos cientos. Esto también es algo que mido - cuántos eventos ocurrieron dentro de un horizonte de tiempo fijo.

past = (time < time[:, None]) & (time>(time- horizon)[:, None]

plt.imshow(past)pasado

El primer problema - la creación de la matriz como arriba para vectores de observación largos es el consumo de tiempo. ¿Hay una mejor manera de crear tal matriz? La matriz presente representa datos reales durante un día, pero esto también puede ser más largo (hasta 50.000 observaciones únicas pero lo que estoy buscando es escalabilidad también).

Más tarde uso TensorFlow para calcular la estadística deseada (primera matrices multiplicadas por sí mismos - entonces sólo tengo datos donde past fue verdadero y posterior cálculo de estadística deseada (medio, cuenta o lo que quiera en filas de matriz producida). Lo que se devuelve es vector de forma==parameters. forma.

La segunda pregunta - ¿Hay una mejor manera de hacer eso? Mejor claro que me refiero más rápido.

EDIT Código de muestra

import datetime
import matplotlib.pyplot as plt


def multiply_time(param, time):
    if param.shape[0] == 1 or param.ndim == 1:
        _temp_param = np.ma.masked_equal(param * time, 0).data
    else:
        _temp_param = np.ma.masked_equal(np.sum(param, axis=1) * time, 0).data

    return_param = np.nanmean( np.where(_temp_param != 0, _temp_param, np.nan), axis=1)

    return return_param


horizon = np.timedelta64(10,'s')
increment = np.timedelta64(1,'s')

vector_len = 100
parameters = np.random.rand(vector_len)
# create time vector where distances between elements are not even
increment_vec = np.cumsum(np.random.randint(0,10,vector_len)*increment)
time = np.datetime64(datetime.datetime.now()) + increment_vec

past = (time < time[:, None]) & (time > (time - horizon )[:, None])
plt.imshow(past)
result = multiply_time(parameters, past)

import pandas as pd
pd_result = pd.DataFrame(parameters).rolling(10,1).mean()
plt.plot(time,result, c='r', label='desired')
plt.plot(time,parameters,c='g', label='original')
plt.plot(time,pd_result,c='b', label='pandas')
plt.legend()
plt.show()```


EDI2:

I guess we can close as answer with pandas rolling gives best results.

Pregunta hecha hace 3 años, 4 meses, 28 días - Por scriptsorcerer4f7e


2 Respuestas:

  • Para calcular el promedio móvil para una ventana de tiempo fija sin utilizar un bucle, puedes considerar utilizar la función rolling de pandas. Aquí tienes un ejemplo de cómo podrías aplicarla a tu código de muestra:

    • Primero, convierte tus arrays numpy de `time` y `parameters` en un DataFrame de pandas para facilitar el trabajo con la función rolling.
    • Luego, utiliza la función rolling sobre los datos para calcular el promedio móvil para la ventana de tiempo específica.

    Aquí te dejo un ejemplo de cómo podrías hacerlo:

    python
    import pandas as pd
    import numpy as np
    
    

    Convertir los arrays numpy a DataFrame de pandas

    df = pd.DataFrame({'time': time, 'parameters': parameters})

    Ordenar el DataFrame por la columna de time

    df = df.sort_values('time')

    Definir el periodo de la ventana móvil

    window_size = 10

    por ejemplo, 10 segundos

    Calcular el promedio móvil para la ventana de tiempo fija

    df['rolling_mean'] = df['parameters'].rolling(window=f'{window_size}s', on='time').mean()

    Mostrar el resultado

    print(df)

    Este código utilizará la función rolling para calcular el promedio móvil para una ventana de tiempo fija de 10 segundos (puedes ajustar el tamaño de la ventana según tus requerimientos). Luego puedes usar la columna 'rolling_mean' en el DataFrame resultante para visualizar o realizar análisis adicionales.

    Espero que esta solución te sea de ayuda. ¡Déjame saber si necesitas más ayuda!

    Respondida el Dec 18, 2020 a las 21:10 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Mejor enfoque usando Pandas

    El enfoque más eficiente para calcular el promedio móvil para una ventana de tiempo fija utilizando Pandas es usar la función rolling(). Esta función crea un objeto Rolling que permite aplicar operaciones a un conjunto de datos sobre una ventana deslizante de observaciones.

    Aquí tienes un ejemplo de cómo puedes utilizar la función rolling() para calcular el promedio móvil para una ventana de tiempo de 10 segundos:

    python
    import pandas as pd
    
    

    Crea un DataFrame con los datos

    df = pd.DataFrame({ "time": pd.date_range('2023-01-01', '2023-01-02', freq='1s'), "parameters": np.random.rand(1440) })

    Calcula el promedio móvil usando una ventana de 10 segundos

    df['rolling_mean'] = df['parameters'].rolling('10s').mean()

    El objeto rolling_mean será una serie de Pandas que contiene el promedio móvil para cada observación en el DataFrame.

    Ventajas de usar Pandas

    Eficiencia: Pandas está optimizado para el procesamiento de datos y proporciona funciones eficientes para el cálculo de promedios móviles. Facilidad de uso: La función rolling() es fácil de usar y proporciona una interfaz intuitiva para trabajar con ventanas de tiempo. Escalabilidad: Pandas puede manejar conjuntos de datos grandes de forma eficiente.

    Respuestas a tus preguntas específicas

    Primera pregunta: La matriz pasado se puede crear de forma más eficiente utilizando la función where() de NumPy:

    python
    past = np.where((time < time[:, None]) & (time > (time - horizon)[:, None]), 1, 0)
    

    Segunda pregunta:* El uso de Pandas con la función rolling() es el enfoque más rápido para calcular promedios móviles para ventanas de tiempo fijas en conjuntos de datos grandes.

    Respondida el Dec 18, 2020 a las 21:15 - por Gemini

    Votos positivos: 0 | Votos negativos: 0