Qual é o caminho mais rápido para se repetidamente reamostrar timeseries de dados da mesma forma, a partir horária anual em python

0

Pergunta

Qual é o caminho mais rápido para se repetidamente reamostrar timeseries de dados da mesma forma?

Problema: eu tenho 30 anos de uma hora timeseries que eu quero re-anual e por ano civil (resample regra 'COMO'). Eu preciso tanto encontrar a média de cada ano e a soma. Não há nenhuma falta de horas. Eu, então, precisa fazer isso mais de 10.000 vezes. Para o script que eu estou escrevendo, este passo de reamostragem leva de longe a maior parte do tempo e é o fator limitante no que respeita à optimização do tempo de execução. Porque dos anos bissextos, o que não reamostrar por um consistente 8760 horas, e a cada ano tem 8784 horas.

Exemplo de código:

import pandas as pd
import numpy as np
import time

hourly_timeseries = pd.DataFrame(
    index=pd.date_range(
    pd.Timestamp(2020, 1, 1, 0, 0),
    pd.Timestamp(2050, 12, 31, 23, 30),
    freq="60min")
)
hourly_timeseries['value'] = np.random.rand(len(hourly_timeseries))
# Constraints imposed by wider problem:
# 1. each hourly_timeseries is unique
# 2. each hourly_timeseries is the same shape and has the same datetimeindex
# 3. a maximum of 10 timeseries can be grouped as columns in dataframe
start_time = time.perf_counter()
for num in range(100): # setting as 100 so it runs faster, this is 10,000+ in practice
    yearly_timeseries_mean = hourly_timeseries.resample('AS').mean() # resample by calendar year
    yearly_timeseries_sum = hourly_timeseries.resample('AS').sum()
finish_time = time.perf_counter()
print(f"Ran in {start_time - finish_time:0.4f} seconds")
>>> Ran in -3.0516 seconds

Soluções de eu ter explorado:

  1. Eu tenho feito algumas melhorias de velocidade agregando vários timeseries em uma dataframe e reamostragem-los ao mesmo tempo; no entanto, devido às restrições do set-up do maior problema que eu estou resolvendo, eu estou limitado a ter 10 timeseries em cada dataframe. Portanto, o problema ainda permanece: existe uma maneira de acelerar drasticamente o reamostragem de timeseries de dados se você sabe a forma da matriz será sempre o mesmo?
  2. Eu também olhei para o uso de numba, mas isso não faz pandas funções mais rápido.

Possíveis soluções que o som razoável, mas não posso te encontrar depois de pesquisar:

  1. reamostrar 3D matriz de timeseries de dados com numpy
  2. Cache de índice que está sendo aumentada e, em seguida, de alguma forma, fazer cada reamostrar após a primeira reamostrar muito mais rápido

Obrigado pela sua ajuda :)

1

Melhor resposta

0

Como eu escrevi no comentário, eu preparei índices para cada ano e os usou para calcular a soma muito para cada ano mais rápido.

Em seguida, removido desnecessários cálculo de soma sob a dizer, em vez disso, o cálculo da média como sum/length_of_indices para cada ano.

Para N=1000 seus ~9x mais rápido

import pandas as pd
import numpy as np
import time

hourly_timeseries = pd.DataFrame(
    index=pd.date_range(
    pd.Timestamp(2020, 1, 1, 0, 0),
    pd.Timestamp(2050, 12, 31, 23, 30),
    freq="60min")
)
hourly_timeseries['value'] = np.random.rand(len(hourly_timeseries))
# Constraints imposed by wider problem:
# 1. each hourly_timeseries is unique
# 2. each hourly_timeseries is the same shape and has the same datetimeindex
# 3. a maximum of 10 timeseries can be grouped as columns in dataframe
start_time = time.perf_counter()
for num in range(100): # setting as 100 so it runs faster, this is 10,000+ in practice
    yearly_timeseries_mean = hourly_timeseries.resample('AS').mean() # resample by calendar year
    yearly_timeseries_sum = hourly_timeseries.resample('AS').sum()
finish_time = time.perf_counter()
print(f"Ran in {finish_time - start_time:0.4f} seconds")


start_time = time.perf_counter()
events_years = hourly_timeseries.index.year
unique_years = np.sort(np.unique(events_years))
indices_per_year = [np.where(events_years == year)[0] for year in unique_years]
len_indices_per_year = np.array([len(year_indices) for year_indices in indices_per_year])
for num in range(100):  # setting as 100 so it runs faster, this is 10,000+ in practice
    temp = hourly_timeseries.values
    yearly_timeseries_sum2 = np.array([np.sum(temp[year_indices]) for year_indices in indices_per_year])
    yearly_timeseries_mean2 = yearly_timeseries_sum2 / len_indices_per_year

finish_time = time.perf_counter()
print(f"Ran in {finish_time - start_time:0.4f} seconds")
assert np.allclose(yearly_timeseries_sum.values.flatten(), yearly_timeseries_sum2)
assert np.allclose(yearly_timeseries_mean.values.flatten(), yearly_timeseries_mean2)
Ran in 0.9950 seconds
Ran in 0.1386 seconds
2021-11-21 21:00:47

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................