Skip to content

Commit

Permalink
Improve the Guess of Window Length for Moving Average Trends #238
Browse files Browse the repository at this point in the history
  • Loading branch information
antoinecarme committed Apr 2, 2023
1 parent 22b10a1 commit d7f5372
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 20 deletions.
14 changes: 12 additions & 2 deletions pyaf/TS/DateTime_Functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def guess_time_resolution(self, iEstimTime):
return eTimeResolution.YEAR;


def get_lags_for_time_resolution(self):
def get_lags_for_time_resolution(self, iResolution):
# self.mOptions.mMaxAROrder is set to 64 by default, Which covers all these resolutions.
if(not self.isPhysicalTime()):
return None;
Expand All @@ -116,7 +116,17 @@ def get_lags_for_time_resolution(self):
lARORder[eTimeResolution.HOUR] = 24
lARORder[eTimeResolution.DAY] = 31
lARORder[eTimeResolution.MONTH] = 12
return lARORder.get(self.mResolution , None)
return lARORder.get(iResolution , None)

def get_moving_window_lengths_for_time_resolution(self, iResolution):
# self.mOptions.mMovingAverageLengths self.mOptions.mMovingMedianLengths
lWindows = {}
lWindows[eTimeResolution.SECOND] = [60] # Minute
lWindows[eTimeResolution.MINUTE] = [60] # Hour
lWindows[eTimeResolution.HOUR] = [12, 24] # Half-Day, Day
lWindows[eTimeResolution.DAY] = [5, 7, 30] # Business Week, Week, Month
lWindows[eTimeResolution.MONTH] = [3, 6, 12] # 3, 6 and 12 months
return lWindows.get(iResolution , [])


def adaptTimeDeltaToTimeResolution(self, iResolution, iTimeDelta):
Expand Down
5 changes: 1 addition & 4 deletions pyaf/TS/Options.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ def __init__(self):
self.mPytorch_Options = None
self.mKeras_Options = None
self.mVotingMethod = "Condorcet" # Or None for Legacy Method (backward compatibility with PyAF 4.0).
self.mMovingWindowLengths = None # [5, 7, 12, 24 , 30, 60];
self.disableDebuggingOptions();

def disableDebuggingOptions(self):
Expand All @@ -236,8 +237,6 @@ def disableDebuggingOptions(self):
def enable_slow_mode(self):
self.set_active_models_for_slow_mode()
self.mQuantiles = [5, 10, 20]; # quintiles, deciles, and vingtiles;)
self.mMovingAverageLengths = [5, 7, 12, 24 , 30, 60];
self.mMovingMedianLengths = [5, 7, 12, 24 , 30, 60];
# PyAF does not detect complex seasonal patterns #73.
# use unlimited cycle lengths in slow mode
self.mCycleLengths = None;
Expand All @@ -252,8 +251,6 @@ def enable_slow_mode(self):
def enable_fast_mode(self):
self.set_active_models_for_fast_mode()
self.mQuantiles = [5, 10, 20]; # quintiles, deciles, and vingtiles;)
self.mMovingAverageLengths = [5, 7, 12, 24 , 30, 60];
self.mMovingMedianLengths = [5, 7, 12, 24 , 30, 60];

self.mCycleLengths = [5, 7, 12, 24 , 30, 60];

Expand Down
28 changes: 14 additions & 14 deletions pyaf/TS/SignalDecomposition_Trend.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ def __init__(self, iWindow):
self.mWindow = iWindow;
self.mFormula = self.mOutName;
self.mComplexity = tscomplex.eModelComplexity.Medium;

def fit_specific(self):
self.mOutName = self.mOutName + "(" + str(self.mWindow) + ")";
self.mFormula = self.mOutName;

def fit_specific(self):
self.mMean = self.mSplit.getEstimPart(self.mTrendFrame)[self.mSignal].mean()


Expand All @@ -161,10 +161,10 @@ def __init__(self, iWindow):
self.mWindow = iWindow;
self.mFormula = self.mOutName;
self.mComplexity = tscomplex.eModelComplexity.High;

def fit_specific(self):
self.mOutName = self.mOutName + "(" + str(self.mWindow) + ")";
self.mFormula = self.mOutName;

def fit_specific(self):
self.mMean = self.mSplit.getEstimPart(self.mTrendFrame)[self.mSignal].mean()


Expand Down Expand Up @@ -264,22 +264,22 @@ def defineTrends(self):

if(N > 2 and self.mOptions.mActiveTrends['PolyTrend']):
self.mTrendList = self.mTrendList + [cPolyTrend()]


lWindows = self.mTimeInfo.get_moving_window_lengths_for_time_resolution()
if(N > 2 and self.mOptions.mActiveTrends['MovingAverage']):
for i in self.mOptions.mMovingAverageLengths:
if(self.needMovingTrend(self.mSignalFrame , i)):
self.mTrendList = self.mTrendList + [cMovingAverageTrend(i)]
for lLength in lWindows:
if(self.needMovingTrend(self.mSignalFrame , lLength)):
self.mTrendList = self.mTrendList + [cMovingAverageTrend(lLength)]

if(N > 2 and self.mOptions.mActiveTrends['MovingMedian']):
for i in self.mOptions.mMovingMedianLengths:
if(self.needMovingTrend(self.mSignalFrame , i)):
self.mTrendList = self.mTrendList + [cMovingMedianTrend(i)]
for lLength in lWindows:
if(self.needMovingTrend(self.mSignalFrame , lLength)):
self.mTrendList = self.mTrendList + [cMovingMedianTrend(lLength)]
if(len(self.mTrendList) == 0):
self.mTrendList = [cConstantTrend()];

# logger = tsutil.get_pyaf_logger();
# logger.info("ACTIVE_TRENDS" + str(self.mOptions.mActiveTrends));
# logger.info("TRENDS" + str([tr.mOutName for tr in self.mTrendList]));
# tsutil.print_pyaf_detailed_info("ACTIVE_TRENDS" + str(self.mOptions.mActiveTrends));
# tsutil.print_pyaf_detailed_info("TRENDS" + str([tr.mOutName for tr in self.mTrendList]));



Expand Down
8 changes: 8 additions & 0 deletions pyaf/TS/Time.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ def isPhysicalTime(self):
lHelper = dtfunc.cDateTime_Helper()
return lHelper.isPhysicalTime(self.mSignalFrame[self.mTime])

def get_moving_window_lengths_for_time_resolution(self):
if(not self.isPhysicalTime()):
return self.mOptions.mMovingWindowLengths or [];
if(self.mOptions.mMovingWindowLengths is not None):
return self.mOptions.mMovingWindowLengths
lHelper = dtfunc.cDateTime_Helper()
return lHelper.get_moving_window_lengths_for_time_resolution(self.mResolution)


def analyzeSeasonals(self):
if(not self.isPhysicalTime()):
Expand Down

0 comments on commit d7f5372

Please sign in to comment.