From 985e91f2ee412852037d178feeb0c3d86094c06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=C3=B4nio=20C=C3=A2ndido?= Date: Thu, 30 May 2019 10:07:32 -0300 Subject: [PATCH] Bugfixes and improvements on benchmark methods --- pyFTS/benchmarks/BSTS.py | 1 + pyFTS/benchmarks/arima.py | 22 ++++++++++++---- pyFTS/benchmarks/quantreg.py | 12 ++++++--- pyFTS/common/Util.py | 49 +++++++++++++++++++++++++++++++++++- pyFTS/tests/general.py | 28 +++++++++++++++------ 5 files changed, 95 insertions(+), 17 deletions(-) diff --git a/pyFTS/benchmarks/BSTS.py b/pyFTS/benchmarks/BSTS.py index f0393ee..7cf6b27 100644 --- a/pyFTS/benchmarks/BSTS.py +++ b/pyFTS/benchmarks/BSTS.py @@ -21,6 +21,7 @@ class ARIMA(fts.FTS): self.has_point_forecasting = True self.has_interval_forecasting = True self.has_probability_forecasting = True + self.uod_clip = False self.model = None self.model_fit = None self.trained_data = None diff --git a/pyFTS/benchmarks/arima.py b/pyFTS/benchmarks/arima.py index 3980310..8f0c29a 100644 --- a/pyFTS/benchmarks/arima.py +++ b/pyFTS/benchmarks/arima.py @@ -21,6 +21,7 @@ class ARIMA(fts.FTS): self.has_point_forecasting = True self.has_interval_forecasting = True self.has_probability_forecasting = True + self.uod_clip = False self.model = None self.model_fit = None self.trained_data = None @@ -96,6 +97,11 @@ class ARIMA(fts.FTS): if self.model_fit is None: return np.nan + if 'alpha' in kwargs: + alpha = kwargs.get('alpha',0.05) + else: + alpha = self.alpha + sigma = np.sqrt(self.model_fit.sigma2) l = len(data) @@ -112,8 +118,8 @@ class ARIMA(fts.FTS): if isinstance(mean,(list, np.ndarray)): mean = mean[0] - tmp.append(mean + st.norm.ppf(self.alpha) * sigma) - tmp.append(mean + st.norm.ppf(1 - self.alpha) * sigma) + tmp.append(mean + st.norm.ppf(alpha) * sigma) + tmp.append(mean + st.norm.ppf(1 - alpha) * sigma) ret.append(tmp) @@ -123,6 +129,11 @@ class ARIMA(fts.FTS): if self.model_fit is None: return np.nan + if 'alpha' in kwargs: + alpha = kwargs.get('alpha',0.05) + else: + alpha = self.alpha + smoothing = kwargs.get("smoothing",0.5) sigma = np.sqrt(self.model_fit.sigma2) @@ -138,8 +149,8 @@ class ARIMA(fts.FTS): hsigma = (1 + k*smoothing)*sigma - tmp.append(nmeans[k] + st.norm.ppf(self.alpha) * hsigma) - tmp.append(nmeans[k] + st.norm.ppf(1 - self.alpha) * hsigma) + tmp.append(nmeans[k] + st.norm.ppf(alpha) * hsigma) + tmp.append(nmeans[k] + st.norm.ppf(1 - alpha) * hsigma) ret.append(tmp) @@ -206,4 +217,5 @@ class ARIMA(fts.FTS): ret.append(dist) - return ret \ No newline at end of file + return ret + diff --git a/pyFTS/benchmarks/quantreg.py b/pyFTS/benchmarks/quantreg.py index e1c792e..91c7cb6 100644 --- a/pyFTS/benchmarks/quantreg.py +++ b/pyFTS/benchmarks/quantreg.py @@ -19,6 +19,7 @@ class QuantileRegression(fts.FTS): self.has_point_forecasting = True self.has_interval_forecasting = True self.has_probability_forecasting = True + self.uod_clip = False self.benchmark_only = True self.min_order = 1 self.alpha = kwargs.get("alpha", 0.05) @@ -96,7 +97,7 @@ class QuantileRegression(fts.FTS): def forecast_ahead_interval(self, ndata, steps, **kwargs): - smoothing = kwargs.get("smoothing", 0.9) + smoothing = kwargs.get("smoothing", 0.1) l = len(ndata) @@ -110,7 +111,9 @@ class QuantileRegression(fts.FTS): for k in np.arange(self.order, steps+self.order): intl = self.point_to_interval(nmeans[k - self.order: k], self.lower_qt, self.upper_qt) - ret.append([intl[0]*(1 + k*smoothing), intl[1]*(1 + k*smoothing)]) + tmpk = k-self.order + + ret.append([intl[0]*(1 + (tmpk*smoothing)), intl[1]*(1 + (tmpk*smoothing))]) return ret[-steps:] @@ -136,7 +139,7 @@ class QuantileRegression(fts.FTS): return ret def forecast_ahead_distribution(self, ndata, steps, **kwargs): - smoothing = kwargs.get("smoothing", 0.9) + smoothing = kwargs.get("smoothing", 0.1) l = len(ndata) @@ -154,7 +157,8 @@ class QuantileRegression(fts.FTS): intervals = [[nmeans[self.order], nmeans[self.order]]] for qt in self.dist_qt: intl1 = self.point_to_interval(nmeans[k - self.order: k], qt[0], qt[1]) - intl2 = [intl1[0] * (1 + k * smoothing), intl1[1] * (1 + k * smoothing)] + tmpk = k - self.order + intl2 = [intl1[0] * (1 + (tmpk * smoothing)), intl1[1] * (1 + (tmpk * smoothing))] intervals.append(intl2) dist.append_interval(intervals) diff --git a/pyFTS/common/Util.py b/pyFTS/common/Util.py index 8bf054f..ade0419 100644 --- a/pyFTS/common/Util.py +++ b/pyFTS/common/Util.py @@ -244,7 +244,7 @@ def plot_interval(axis, intervals, order, label, color='red', typeonlegend=False upper = [kk[1] for kk in intervals] mi = min(lower) * 0.95 ma = max(upper) * 1.05 - for k in np.arange(0, order): + for k in np.arange(0, order+1): lower.insert(0, None) upper.insert(0, None) if typeonlegend: label += " (Interval)" @@ -253,6 +253,53 @@ def plot_interval(axis, intervals, order, label, color='red', typeonlegend=False return [mi, ma] +def plot_interval2(intervals, data, **kwargs): + ''' + Plot forecasted intervals on matplotlib + + :param intervals: list of forecasted intervals + :param data: the original test sample + :keyword start_at: the time index (inside of data) to start to plot the intervals + :keyword label: figure label + :keyword color: matplotlib color name + :keyword typeonlegend: + :keyword ls: matplotlib line style + :keyword linewidth: matplotlib width + :return: a list [lower, upper] with the minimum and maximum bounds of the intervals + ''' + + l = len(intervals) + + start_at = kwargs.get('start_at', 1) + + ax = kwargs.get('ax', None) + if ax is None: + fig, ax = plt.subplots(nrows=1, ncols=1, figsize=[15, 5]) + + for k in np.arange(0, start_at-1): + intervals.insert(0, [None,None]) + + intervals.insert(start_at, [data[start_at], data[start_at]]) + + lower = [kk[0] for kk in intervals] + upper = [kk[1] for kk in intervals] + mi = min(lower) * 0.95 + ma = max(upper) * 1.05 + + typeonlegend = kwargs.get('typeonlegend', False) + color = kwargs.get('color', 'red') + label = kwargs.get('label','') + linewidth = kwargs.get('linewidth', 1) + + ls = kwargs.get('ls','-') + + if typeonlegend: label += " (Interval)" + ax.plot(lower, color=color, label=label, ls=ls,linewidth=linewidth) + ax.plot(upper, color=color, ls=ls,linewidth=linewidth) + return [mi, ma] + + + def plot_rules(model, size=[5, 5], axis=None, rules_by_axis=None, columns=1): ''' Plot the FLRG rules of a FTS model on a matplotlib axis diff --git a/pyFTS/tests/general.py b/pyFTS/tests/general.py index c6c197a..e6b1358 100644 --- a/pyFTS/tests/general.py +++ b/pyFTS/tests/general.py @@ -13,20 +13,34 @@ from pyFTS.partitioners import Grid, Entropy, Util as pUtil, Simple from pyFTS.benchmarks import benchmarks as bchmk, Measures from pyFTS.models import chen, yu, cheng, ismailefendi, hofts, pwfts, tsaur, song, sadaei from pyFTS.common import Transformations, Membership - +from pyFTS.benchmarks import arima, quantreg, BSTS from pyFTS.fcm import fts, common, GA from pyFTS.data import Enrollments, TAIEX -x = [k for k in np.arange(-2*np.pi, 2*np.pi, 0.15)] -y = [np.sin(k) for k in x] +data = TAIEX.get_data() -from pyFTS.probabilistic import ProbabilityDistribution +train = data[:500] +test = data[500:1000] -pd = ProbabilityDistribution.ProbabilityDistribution(type='histogram', data=y, num_bins=30) +model = quantreg.QuantileRegression(order=1, dist=True) +model.fit(train) -print(pd.quantile([.5])) -print(pd.cdf) +horizon=5 + +#points = model.predict(test[:10], type='point', steps_ahead=horizon) + +intervals = model.predict(test[:10], type='interval', alpha=.05, smoothing=0.01, steps_ahead=horizon) +print(test[:10]) +print(intervals) +distributions = model.predict(test[:10], type='distribution', steps_ahead=horizon, num_bins=100) + + +fig, ax = plt.subplots(nrows=1, ncols=1,figsize=[15,5]) + +ax.plot(test[:10], label='Original',color='black') +cUtil.plot_interval(ax, intervals, model.order, label='ensemble') +cUtil.plot_distribution2(distributions, test[:10], start_at=2, ax=ax, cmap="Blues") ''' model = fts.FCM_FTS(partitioner=fs, order=1)