diff --git a/benchmarks/Measures.py b/benchmarks/Measures.py index 990131f..e39335c 100644 --- a/benchmarks/Measures.py +++ b/benchmarks/Measures.py @@ -42,9 +42,19 @@ def UStatistic(targets, forecasts): naive = [] y = [] for k in np.arange(0,l-1): - y.append(((forecasts[k+1] - targets[k+1])/targets[k]) ** 2) - naive.append(((targets[k + 1] - targets[k]) / targets[k]) ** 2) - return np.sqrt(sum(y)/sum(naive)) + y.append((forecasts[k ] - targets[k ]) ** 2) + naive.append((targets[k + 1] - targets[k]) ** 2) + return np.sqrt(sum(y) / sum(naive)) + + +# Theil’s Inequality Coefficient +def TheilsInequality(targets, forecasts): + res = targets - forecasts + t = len(res) + us = np.sqrt(sum([u**2 for u in res])) + ys = np.sqrt(sum([y**2 for y in targets])) + fs = np.sqrt(sum([f**2 for f in forecasts])) + return us / (ys + fs) # Q Statistic for Box-Pierce test diff --git a/benchmarks/ResidualAnalysis.py b/benchmarks/ResidualAnalysis.py index a81361f..83d203e 100644 --- a/benchmarks/ResidualAnalysis.py +++ b/benchmarks/ResidualAnalysis.py @@ -19,7 +19,6 @@ def ChiSquared(q,h): return p - def compareResiduals(data, models): ret = "Model & Order & Mean & STD & Box-Pierce & Box-Ljung & P-value \\\\ \n" for mfts in models: @@ -29,12 +28,12 @@ def compareResiduals(data, models): sig = np.std(res) ret += mfts.shortname + " & " ret += str(mfts.order) + " & " - ret += str(mu) + " & " - ret += str(sig) + " & " + ret += str(round(mu,2)) + " & " + ret += str(round(sig,2)) + " & " q1 = Measures.BoxPierceStatistic(res, 10) - ret += str(q1) + " & " + ret += str(round(q1,2)) + " & " q2 = Measures.BoxLjungStatistic(res, 10) - ret += str(q2) + " & " + ret += str(round(q2,2)) + " & " ret += str(ChiSquared(q2, 10)) ret += " \\\\ \n" return ret diff --git a/benchmarks/benchmarks.py b/benchmarks/benchmarks.py index aa042aa..22c4c7d 100644 --- a/benchmarks/benchmarks.py +++ b/benchmarks/benchmarks.py @@ -14,7 +14,8 @@ from pyFTS.common import Membership, FuzzySet, FLR, Transformations, Util from pyFTS import fts, chen, yu, ismailefendi, sadaei, hofts, hwang, pfts, ifts -def allPointForecasters(data_train, data_test, partitions, max_order=3,save=False, file=None, tam=[20, 5]): +def allPointForecasters(data_train, data_test, partitions, max_order=3, statistics=True, residuals=True, series=True, + save=False, file=None, tam=[20, 5]): models = [naive.Naive, chen.ConventionalFTS, yu.WeightedFTS, ismailefendi.ImprovedWeightedFTS, sadaei.ExponentialyWeightedFTS, hofts.HighOrderFTS, pfts.ProbabilisticFTS] @@ -44,24 +45,27 @@ def allPointForecasters(data_train, data_test, partitions, max_order=3,save=Fals colors.append(all_colors[count]) count += 10 - print(getPointStatistics(data_test, objs)) + if statistics: + print(getPointStatistics(data_test, objs)) - print(ResidualAnalysis.compareResiduals(data_test, objs)) + if residuals: + print(ResidualAnalysis.compareResiduals(data_test, objs)) + ResidualAnalysis.plotResiduals(data_test, objs, save=save, file=file, tam=[tam[0], 5 * tam[1]]) - plotComparedSeries(data_test, objs, colors, typeonlegend=False, save=save, file=file, tam=tam, intervals=False) - - ResidualAnalysis.plotResiduals(data_test, objs, save=save, file=file, tam=[tam[0],5*tam[1]]) + if series: + plotComparedSeries(data_test, objs, colors, typeonlegend=False, save=save, file=file, tam=tam, intervals=False) def getPointStatistics(data, models, externalmodels = None, externalforecasts = None): - ret = "Model & Order & RMSE & MAPE & Theil's U \\\\ \n" + ret = "Model & Order & RMSE & MAPE & Theil's U & Theil's I \\\\ \n" for fts in models: forecasts = fts.forecast(data) ret += fts.shortname + " & " ret += str(fts.order) + " & " ret += str(round(Measures.rmse(np.array(data[fts.order:]), np.array(forecasts[:-1])), 2)) + " & " ret += str(round(Measures.mape(np.array(data[fts.order:]), np.array(forecasts[:-1])), 2))+ " & " - ret += str(round(Measures.UStatistic(np.array(data[fts.order:]), np.array(forecasts[:-1])), 2)) + ret += str(round(Measures.UStatistic(np.array(data[fts.order:]), np.array(forecasts[:-1])), 2))+ " & " + ret += str(round(Measures.TheilsInequality(np.array(data[fts.order:]), np.array(forecasts[:-1])), 4)) ret += " \\\\ \n" if externalmodels is not None: l = len(externalmodels) diff --git a/benchmarks/naive.py b/benchmarks/naive.py index 9a86875..7b6da95 100644 --- a/benchmarks/naive.py +++ b/benchmarks/naive.py @@ -12,3 +12,4 @@ class Naive(fts.FTS): def forecast(self, data): return [k for k in data] + diff --git a/common/Transformations.py b/common/Transformations.py index 24fb58b..7c35486 100644 --- a/common/Transformations.py +++ b/common/Transformations.py @@ -3,11 +3,40 @@ import math from pyFTS import * -def differential(original, lags=1): - n = len(original) - diff = [original[t - lags] - original[t] for t in np.arange(lags, n)] - for t in np.arange(0, lags): diff.insert(0, 0) - return np.array(diff) +class Transformation(object): + + def __init__(self, parameters): + self.isInversible = True + self.parameters = parameters + + def apply(self,data,param): + pass + + def inverse(self,data, param): + pass + + def __str__(self): + return self.__class__.__name__ + '(' + str(self.parameters) + ')' + + +class Differential(Transformation): + + def __init__(self, parameters): + super(Differential, self).__init__(parameters) + self.lag = parameters + + def apply(self, data, param=None): + if param is not None: + self.lag = param + n = len(data) + diff = [data[t - self.lag] - data[t] for t in np.arange(self.lag, n)] + for t in np.arange(0, self.lag): diff.insert(0, 0) + return np.array(diff) + + def inverse(self,data, param): + n = len(data) + inc = [data[t] + param[t] for t in np.arange(1, n)] + return np.array(inc) def boxcox(original, plambda): diff --git a/fts.py b/fts.py index 1431160..cc4322a 100644 --- a/fts.py +++ b/fts.py @@ -17,6 +17,8 @@ class FTS(object): self.hasIntervalForecasting = False self.hasDistributionForecasting = False self.dump = False + self.transformations = [] + self.transformations_param = [] def fuzzy(self, data): best = {"fuzzyset": "", "membership": 0.0} @@ -54,6 +56,31 @@ class FTS(object): ret = np.array([s.centroid for s in flrg.RHS]) return ret + def appendTransformation(self, transformation): + self.transformations.append(transformation) + + def doTransformations(self,data,params=None): + ndata = data + if params is None: + params = [ None for k in self.transformations] + c = 0 + for t in self.transformations: + ndata = t.apply(ndata,params[c]) + c += 1 + + return ndata + + def doInverseTransformations(self,data,params=None): + ndata = data + if params is None: + params = [None for k in self.transformations] + c = 0 + for t in reversed(self.transformations): + ndata = t.inverse(ndata, params[c]) + c += 1 + + return ndata + def __str__(self): tmp = self.name + ":\n" for r in sorted(self.flrgs):