Co je nejrychlejší způsob, jak opakovaně převzorkování série dat stejného tvaru z hodinové roční v pythonu

0

Otázka

Co je nejrychlejší způsob, jak opakovaně převzorkování série dat stejného tvaru?

Problém: mám 30 let hodinový série, které chci převzorkování na roční a kalendářní rok (resample pravidlo "JAKO"). Potřebuji, aby oba našli na mysli v každém roce a součet. Neexistují žádné chybějící hodiny. Pak jsem třeba udělat více než 10.000 krát. Za scénář píšu, to převzorkování krok zabere zdaleka nejvíce času a je limitujícím faktorem s ohledem na optimalizaci běhu. Protože přestupných let, nikdo nemůže resample o důsledné 8760 hodin, jako každý čtvrtý rok má 8784 hodin.

Příklad kódu:

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

Řešení jsem se zabýval:

  1. Udělal jsem několik vylepšení rychlosti agregací více zprávami na datovém a převzorkování je ve stejnou dobu; nicméně, vzhledem k omezení nastavení širší problém řeším, jsem omezen na to, že 10 série v každém datovém. Proto, problém stále zůstává: je tam způsob, jak dramaticky speed up převzorkování pro série dat, pokud víte, tvar pole bude vždy stejný?
  2. Také jsem se podíval do použití numba, ale to neznamená, že pandy funkce rychlejší.

Možné řešení, které zní rozumně, ale nemohu najít po zkoumání:

  1. převzorkování 3D pole série dat s numpy
  2. Cache index, který je převzorkování a pak nějak udělat každý převzorkovat po první převzorkování mnohem rychleji

Díky za pomoc :)

1

Nejlepší odpověď

0

Jak jsem psal v komentáři, jsem připraven indexy pro každý rok a použít je pro výpočet částky za každý rok rychleji.

Dále jsem odstranil zbytečné výpočet součtu pod tím znovu, namísto výpočtu říct, jak sum/length_of_indices pro každý rok.

Pro N=1000 ~9x rychlejší

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

V jiných jazycích

Tato stránka je v jiných jazycích

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