|
@@ -50,8 +50,12 @@ class Prophet(object):
|
|
|
if input `changepoints` is supplied. If `changepoints` is not supplied,
|
|
if input `changepoints` is supplied. If `changepoints` is not supplied,
|
|
|
then n_changepoints potential changepoints are selected uniformly from
|
|
then n_changepoints potential changepoints are selected uniformly from
|
|
|
the first 80 percent of the history.
|
|
the first 80 percent of the history.
|
|
|
- yearly_seasonality: Fit yearly seasonality. Can be 'auto', True, or False.
|
|
|
|
|
- weekly_seasonality: Fit weekly seasonality. Can be 'auto', True, or False.
|
|
|
|
|
|
|
+ yearly_seasonality: Fit yearly seasonality.
|
|
|
|
|
+ Can be 'auto', True, False, or a number of Fourier terms to generate.
|
|
|
|
|
+ weekly_seasonality: Fit weekly seasonality.
|
|
|
|
|
+ Can be 'auto', True, False, or a number of Fourier terms to generate.
|
|
|
|
|
+ daily_seasonality: Fit daily seasonality.
|
|
|
|
|
+ Can be 'auto', True, False, or a number of Fourier terms to generate.
|
|
|
holidays: pd.DataFrame with columns holiday (string) and ds (date type)
|
|
holidays: pd.DataFrame with columns holiday (string) and ds (date type)
|
|
|
and optionally columns lower_window and upper_window which specify a
|
|
and optionally columns lower_window and upper_window which specify a
|
|
|
range of days around the date to be included as holidays.
|
|
range of days around the date to be included as holidays.
|
|
@@ -84,6 +88,7 @@ class Prophet(object):
|
|
|
n_changepoints=25,
|
|
n_changepoints=25,
|
|
|
yearly_seasonality='auto',
|
|
yearly_seasonality='auto',
|
|
|
weekly_seasonality='auto',
|
|
weekly_seasonality='auto',
|
|
|
|
|
+ daily_seasonality='auto',
|
|
|
holidays=None,
|
|
holidays=None,
|
|
|
seasonality_prior_scale=10.0,
|
|
seasonality_prior_scale=10.0,
|
|
|
holidays_prior_scale=10.0,
|
|
holidays_prior_scale=10.0,
|
|
@@ -154,8 +159,8 @@ class Prophet(object):
|
|
|
for h in self.holidays['holiday'].unique():
|
|
for h in self.holidays['holiday'].unique():
|
|
|
if '_delim_' in h:
|
|
if '_delim_' in h:
|
|
|
raise ValueError('Holiday name cannot contain "_delim_"')
|
|
raise ValueError('Holiday name cannot contain "_delim_"')
|
|
|
- if h in ['zeros', 'yearly', 'weekly', 'yhat', 'seasonal',
|
|
|
|
|
- 'trend']:
|
|
|
|
|
|
|
+ if h in ['zeros', 'yearly', 'weekly', 'daily', 'yhat',
|
|
|
|
|
+ 'seasonal', 'trend']:
|
|
|
raise ValueError('Holiday name {} reserved.'.format(h))
|
|
raise ValueError('Holiday name {} reserved.'.format(h))
|
|
|
|
|
|
|
|
def setup_dataframe(self, df, initialize_scales=False):
|
|
def setup_dataframe(self, df, initialize_scales=False):
|
|
@@ -259,8 +264,9 @@ class Prophet(object):
|
|
|
# convert to days since epoch
|
|
# convert to days since epoch
|
|
|
t = np.array(
|
|
t = np.array(
|
|
|
(dates - pd.datetime(1970, 1, 1))
|
|
(dates - pd.datetime(1970, 1, 1))
|
|
|
- .dt.total_seconds()/(24*3600)
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ .dt.total_seconds()
|
|
|
|
|
+ .astype(np.float)
|
|
|
|
|
+ ) / (3600 * 24.)
|
|
|
return np.column_stack([
|
|
return np.column_stack([
|
|
|
fun((2.0 * (i + 1) * np.pi * t / period))
|
|
fun((2.0 * (i + 1) * np.pi * t / period))
|
|
|
for i in range(series_order)
|
|
for i in range(series_order)
|
|
@@ -354,28 +360,28 @@ class Prophet(object):
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
# Seasonality features
|
|
# Seasonality features
|
|
|
- if self.yearly_seasonality:
|
|
|
|
|
|
|
+ if self.yearly_seasonality > 0:
|
|
|
seasonal_features.append(self.make_seasonality_features(
|
|
seasonal_features.append(self.make_seasonality_features(
|
|
|
df['ds'],
|
|
df['ds'],
|
|
|
365.25,
|
|
365.25,
|
|
|
- 10,
|
|
|
|
|
|
|
+ self.yearly_seasonality,
|
|
|
'yearly',
|
|
'yearly',
|
|
|
))
|
|
))
|
|
|
|
|
|
|
|
- if self.weekly_seasonality:
|
|
|
|
|
|
|
+ if self.weekly_seasonality > 0:
|
|
|
seasonal_features.append(self.make_seasonality_features(
|
|
seasonal_features.append(self.make_seasonality_features(
|
|
|
df['ds'],
|
|
df['ds'],
|
|
|
7,
|
|
7,
|
|
|
- 3,
|
|
|
|
|
|
|
+ self.weekly_seasonality,
|
|
|
'weekly',
|
|
'weekly',
|
|
|
))
|
|
))
|
|
|
|
|
|
|
|
- if self.daily_seasonality:
|
|
|
|
|
|
|
+ if self.daily_seasonality > 0:
|
|
|
seasonal_features.append(self.make_seasonality_features(
|
|
seasonal_features.append(self.make_seasonality_features(
|
|
|
df['ds'],
|
|
df['ds'],
|
|
|
1,
|
|
1,
|
|
|
- 3,
|
|
|
|
|
- 'daily'
|
|
|
|
|
|
|
+ self.daily_seasonality,
|
|
|
|
|
+ 'daily',
|
|
|
))
|
|
))
|
|
|
|
|
|
|
|
if self.holidays is not None:
|
|
if self.holidays is not None:
|
|
@@ -393,21 +399,40 @@ class Prophet(object):
|
|
|
last = self.history['ds'].max()
|
|
last = self.history['ds'].max()
|
|
|
if self.yearly_seasonality == 'auto':
|
|
if self.yearly_seasonality == 'auto':
|
|
|
if last - first < pd.Timedelta(days=730):
|
|
if last - first < pd.Timedelta(days=730):
|
|
|
- self.yearly_seasonality = False
|
|
|
|
|
|
|
+ self.yearly_seasonality = 0
|
|
|
logger.info('Disabling yearly seasonality. Run prophet with '
|
|
logger.info('Disabling yearly seasonality. Run prophet with '
|
|
|
- 'yearly_seasonality=True to override this.')
|
|
|
|
|
|
|
+ 'yearly_seasonality=True to override this.')
|
|
|
else:
|
|
else:
|
|
|
- self.yearly_seasonality = True
|
|
|
|
|
|
|
+ self.yearly_seasonality = 10
|
|
|
|
|
+ elif self.yearly_seasonality is True:
|
|
|
|
|
+ self.yearly_seasonality = 10
|
|
|
|
|
+
|
|
|
if self.weekly_seasonality == 'auto':
|
|
if self.weekly_seasonality == 'auto':
|
|
|
dt = self.history['ds'].diff()
|
|
dt = self.history['ds'].diff()
|
|
|
min_dt = dt.iloc[dt.nonzero()[0]].min()
|
|
min_dt = dt.iloc[dt.nonzero()[0]].min()
|
|
|
if ((last - first < pd.Timedelta(weeks=2)) or
|
|
if ((last - first < pd.Timedelta(weeks=2)) or
|
|
|
(min_dt >= pd.Timedelta(weeks=1))):
|
|
(min_dt >= pd.Timedelta(weeks=1))):
|
|
|
- self.weekly_seasonality = False
|
|
|
|
|
|
|
+ self.weekly_seasonality = 0
|
|
|
logger.info('Disabling weekly seasonality. Run prophet with '
|
|
logger.info('Disabling weekly seasonality. Run prophet with '
|
|
|
- 'weekly_seasonality=True to override this.')
|
|
|
|
|
|
|
+ 'weekly_seasonality=True to override this.')
|
|
|
else:
|
|
else:
|
|
|
- self.weekly_seasonality = True
|
|
|
|
|
|
|
+ self.weekly_seasonality = 3
|
|
|
|
|
+ elif self.weekly_seasonality is True:
|
|
|
|
|
+ self.weekly_seasonality = 3
|
|
|
|
|
+
|
|
|
|
|
+ if self.daily_seasonality == 'auto':
|
|
|
|
|
+ # disabled by default but if the average difference is <1 day
|
|
|
|
|
+ # then we assume there is intra-day modeling
|
|
|
|
|
+ dt = self.history['ds'].diff()
|
|
|
|
|
+ min_dt = dt.iloc[dt.nonzero()[0]].min()
|
|
|
|
|
+ if (min_dt< pd.Timedelta(days=1)):
|
|
|
|
|
+ self.daily_seasonality = 4
|
|
|
|
|
+ logger.info('Enabling daily seasonality. Run prophet with '
|
|
|
|
|
+ 'daily_seasonality=False to override this.')
|
|
|
|
|
+ else:
|
|
|
|
|
+ self.daily_seasonality = 0
|
|
|
|
|
+ elif self.daily_seasonality is True:
|
|
|
|
|
+ self.daily_seasonality = 4
|
|
|
|
|
|
|
|
@staticmethod
|
|
@staticmethod
|
|
|
def linear_growth_init(df):
|
|
def linear_growth_init(df):
|