diff --git a/benchmarks/benchmarks.py b/benchmarks/benchmarks.py index da37924..f2b90da 100644 --- a/benchmarks/benchmarks.py +++ b/benchmarks/benchmarks.py @@ -641,7 +641,8 @@ def compareModelsTable(original, models_fo, models_ho): def simpleSearch_RMSE(train, test, model, partitions, orders, save=False, file=None, tam=[10, 15], - plotforecasts=False, elev=30, azim=144, intervals=False): + plotforecasts=False, elev=30, azim=144, intervals=False,parameters=None): + _3d = len(orders) > 1 ret = [] errors = np.array([[0 for k in range(len(partitions))] for kk in range(len(orders))]) forecasted_best = [] @@ -662,13 +663,16 @@ def simpleSearch_RMSE(train, test, model, partitions, orders, save=False, file=N sets = Grid.GridPartitionerTrimf(train, p) for oc, o in enumerate(orders, start=0): fts = model("q = " + str(p) + " n = " + str(o)) - fts.train(train, sets, o) + fts.train(train, sets, o,parameters=parameters) if not intervals: forecasted = fts.forecast(test) - error = Measures.rmse(np.array(test[o:]), np.array(forecasted[:-1])) + if not fts.hasSeasonality: + error = Measures.rmse(np.array(test[o:]), np.array(forecasted[:-1])) + else: + error = Measures.rmse(np.array(test[o:]), np.array(forecasted)) for kk in range(o): forecasted.insert(0, None) - if plotforecasts: ax0.plot(forecasted, label=fts.name) + if plotforecasts: ax0.plot(forecasted, label=fts.name) else: forecasted = fts.forecastInterval(test) error = 1.0 - Measures.rmse_interval(np.array(test[o:]), np.array(forecasted[:-1])) @@ -683,15 +687,22 @@ def simpleSearch_RMSE(train, test, model, partitions, orders, save=False, file=N # handles0, labels0 = ax0.get_legend_handles_labels() # ax0.legend(handles0, labels0) ax0.plot(test, label="Original", linewidth=3.0, color="black") - ax1 = Axes3D(fig, rect=[0, 1, 0.9, 0.9], elev=elev, azim=azim) + if _3d: ax1 = Axes3D(fig, rect=[0, 1, 0.9, 0.9], elev=elev, azim=azim) if not plotforecasts: ax1 = Axes3D(fig, rect=[0, 1, 0.9, 0.9], elev=elev, azim=azim) # ax1 = fig.add_axes([0.6, 0.5, 0.45, 0.45], projection='3d') - ax1.set_title('Error Surface') - ax1.set_ylabel('Model order') - ax1.set_xlabel('Number of partitions') - ax1.set_zlabel('RMSE') - X, Y = np.meshgrid(partitions, orders) - surf = ax1.plot_surface(X, Y, errors, rstride=1, cstride=1, antialiased=True) + if _3d: + ax1.set_title('Error Surface') + ax1.set_ylabel('Model order') + ax1.set_xlabel('Number of partitions') + ax1.set_zlabel('RMSE') + X, Y = np.meshgrid(partitions, orders) + surf = ax1.plot_surface(X, Y, errors, rstride=1, cstride=1, antialiased=True) + else: + ax1 = fig.add_axes([0, 1, 0.9, 0.9]) + ax1.set_title('Error Curve') + ax1.set_ylabel('Number of partitions') + ax1.set_xlabel('RMSE') + ax0.plot(errors,partitions) ret.append(best) ret.append(forecasted_best) diff --git a/common/FLR.py b/common/FLR.py index 3bd9338..eebcf50 100644 --- a/common/FLR.py +++ b/common/FLR.py @@ -1,7 +1,8 @@ import numpy as np +from pyFTS.common import FuzzySet -class FLR: +class FLR(object): def __init__(self, LHS, RHS): self.LHS = LHS self.RHS = RHS @@ -10,6 +11,15 @@ class FLR: return self.LHS.name + " -> " + self.RHS.name +class IndexedFLR(FLR): + def __init__(self, index, LHS, RHS): + super(IndexedFLR, self).__init__(LHS, RHS) + self.index = index + + def __str__(self): + return str(self.index) + ": "+ self.LHS.name + " -> " + self.RHS.name + + def generateNonRecurrentFLRs(fuzzyData): flrs = {} for i in range(2,len(fuzzyData)): @@ -18,8 +28,22 @@ def generateNonRecurrentFLRs(fuzzyData): ret = [value for key, value in flrs.items()] return ret + def generateRecurrentFLRs(fuzzyData): flrs = [] for i in np.arange(1,len(fuzzyData)): flrs.append(FLR(fuzzyData[i-1],fuzzyData[i])) return flrs + + +def generateIndexedFLRs(sets, indexer, data): + flrs = [] + index = indexer.get_season_of_data(data) + ndata = indexer.get_data(data) + for k in np.arange(0,len(data)-1): + lhs = FuzzySet.getMaxMembershipFuzzySet(ndata[k],sets) + rhs = FuzzySet.getMaxMembershipFuzzySet(ndata[k+1], sets) + season = index[k] + flr = IndexedFLR(season,lhs,rhs) + flrs.append(flr) + return flrs diff --git a/fts.py b/fts.py index c0db302..fad4fb2 100644 --- a/fts.py +++ b/fts.py @@ -16,6 +16,7 @@ class FTS(object): self.hasPointForecasting = True self.hasIntervalForecasting = False self.hasDistributionForecasting = False + self.isMultivariate = False self.dump = False self.transformations = [] self.transformations_param = [] diff --git a/models/msfts.py b/models/msfts.py new file mode 100644 index 0000000..d3681d2 --- /dev/null +++ b/models/msfts.py @@ -0,0 +1,61 @@ +import numpy as np +from pyFTS.common import FuzzySet,FLR +from pyFTS import fts, sfts + +class MultiSeasonalFTS(sfts.SeasonalFTS): + def __init__(self, name, indexer): + super(MultiSeasonalFTS, self).__init__("MSFTS") + self.name = "Multi Seasonal FTS" + self.detail = "" + self.seasonality = 1 + self.hasSeasonality = True + self.hasPointForecasting = True + self.isHighOrder = True + self.isMultivariate = True + self.indexer = indexer + self.flrgs = {} + + def generateFLRG(self, flrs): + flrgs = {} + + for index, season in enumerate(self.indexer.get_season_of_data(flrs),start=0): + + print(index) + print(season) + + if str(season) not in self.flrgs: + flrgs[str(season)] = sfts.SeasonalFLRG(season) + + flrgs[str(season)].append(flrs[index].RHS) + + return (flrgs) + + def train(self, data, sets, order=1, parameters=None): + self.sets = sets + self.seasonality = parameters + ndata = self.indexer.set_data(data,self.doTransformations(self.indexer.get_data(data))) + tmpdata = FuzzySet.fuzzySeries(ndata, sets) + flrs = FLR.generateRecurrentFLRs(tmpdata) + self.flrgs = self.generateFLRG(flrs) + + def forecast(self, data): + + ndata = np.array(self.doTransformations(self.indexer.get_data(data))) + + l = len(ndata) + + ret = [] + + for k in np.arange(1, l): + + season = self.indexer.get_season_index(k) + + flrg = self.flrgs[str(season)] + + mp = self.getMidpoints(flrg) + + ret.append(sum(mp) / len(mp)) + + ret = self.doInverseTransformations(ret, params=[data[self.order - 1:]]) + + return ret diff --git a/models/seasonal/SeasonalIndexer.py b/models/seasonal/SeasonalIndexer.py new file mode 100644 index 0000000..729652c --- /dev/null +++ b/models/seasonal/SeasonalIndexer.py @@ -0,0 +1,102 @@ +import numpy as np + +class SeasonalIndexer(object): + def __init__(self,num_seasons): + self.num_seasons = num_seasons + + def get_season_of_data(self,data): + pass + + def get_season_by_index(self,inde): + pass + + def get_data_by_season(self, data, indexes): + pass + + def get_index_by_season(self, indexes): + pass + + def get_data(self, data): + pass + + +class LinearSeasonalIndexer(SeasonalIndexer): + def __init__(self,seasons): + super(LinearSeasonalIndexer, self).__init__(len(seasons)) + self.seasons = seasons + + def get_season_of_data(self,data): + return self.get_season_by_index(np.arange(0,len(data))) + + def get_season_by_index(self,index): + ret = [] + for ix in index: + if self.num_seasons == 1: + season = ix % self.seasons + else: + season = [] + for seasonality in self.seasons: + print("S ", seasonality) + tmp = ix // seasonality + print("T ", tmp) + season.append(tmp) + #season.append(rest) + + ret.append(season) + + return ret + + def get_index_by_season(self, indexes): + ix = 0; + + for count,season in enumerate(self.seasons): + ix += season*(indexes[count]) + + #ix += indexes[-1] + + return ix + + def get_data(self, data): + return data + + +class DataFrameSeasonalIndexer(SeasonalIndexer): + def __init__(self,index_fields,index_seasons, data_fields): + super(DataFrameSeasonalIndexer, self).__init__(len(index_seasons)) + self.fields = index_fields + self.seasons = index_seasons + self.data_fields = data_fields + + def get_season_of_data(self,data): + ret = [] + for ix in data.index: + season = [] + for c, f in enumerate(self.fields, start=0): + if self.seasons[c] is None: + season.append(data[f][ix]) + else: + season.append(data[f][ix] // self.seasons[c]) + ret.append(season) + return ret + + def get_season_by_index(self,index): + raise Exception("Operation not available!") + + def get_data_by_season(self, data, indexes): + for season in indexes: + for c, f in enumerate(self.fields, start=0): + if self.seasons[c] is None: + data = data[data[f]== season[c]] + else: + data = data[(data[f] // self.seasons[c]) == season[c]] + return data[self.data_fields] + + def get_index_by_season(self, indexes): + raise Exception("Operation not available!") + + def get_data(self, data): + return data[self.data_fields].tolist() + + def set_data(self, data, value): + data[self.data_fields] = value + return data \ No newline at end of file diff --git a/models/seasonal/__init__.py b/models/seasonal/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sfts.py b/sfts.py index 701df7d..3cbfb16 100644 --- a/sfts.py +++ b/sfts.py @@ -1,7 +1,6 @@ import numpy as np from pyFTS.common import FuzzySet,FLR -import fts - +from pyFTS import fts class SeasonalFLRG(fts.FTS): def __init__(self, seasonality): @@ -28,15 +27,19 @@ class SeasonalFTS(fts.FTS): self.detail = "Chen" self.seasonality = 1 self.hasSeasonality = True + self.hasPointForecasting = True + self.isHighOrder = False def generateFLRG(self, flrs): flrgs = [] season = 1 for flr in flrs: + if len(flrgs) < self.seasonality: flrgs.append(SeasonalFLRG(season)) - flrgs[season].append(flr.RHS) + #print(season) + flrgs[season-1].append(flr.RHS) season = (season + 1) % (self.seasonality + 1) @@ -54,16 +57,20 @@ class SeasonalFTS(fts.FTS): def forecast(self, data): - data = np.array(data) - - ndata = self.doTransformations(data) + ndata = np.array(self.doTransformations(data)) l = len(ndata) ret = [] for k in np.arange(1, l): - flrg = self.flrgs[data[k]] + #flrg = self.flrgs[ndata[k]] + + season = (k + 1) % (self.seasonality + 1) + + #print(season) + + flrg = self.flrgs[season-1] mp = self.getMidpoints(flrg) diff --git a/tests/sfts.py b/tests/sfts.py new file mode 100644 index 0000000..1e62ea8 --- /dev/null +++ b/tests/sfts.py @@ -0,0 +1,55 @@ +#!/usr/bin/python +# -*- coding: utf8 -*- + +import os +import numpy as np +import pandas as pd +import matplotlib as plt +import matplotlib.pyplot as plt +from mpl_toolkits.mplot3d import Axes3D + +import pandas as pd +from pyFTS.partitioners import Grid +from pyFTS.common import FLR,FuzzySet,Membership,Transformations +from pyFTS import fts,sfts +from pyFTS.models import msfts +from pyFTS.benchmarks import benchmarks as bchmk +from pyFTS.benchmarks import Measures + +os.chdir("/home/petronio/dados/Dropbox/Doutorado/Disciplinas/AdvancedFuzzyTimeSeriesModels/") + +sonda = pd.read_csv("DataSets/SONDA_BSB_CLEAN.csv", sep=";") + +sonda = sonda[:][527041:] + +sonda.index = np.arange(0,len(sonda.index)) + +sonda_treino = sonda[:1051200] +sonda_teste = sonda[1051201:] + + +#res = bchmk.simpleSearch_RMSE(sonda_treino, sonda_teste, +# sfts.SeasonalFTS,np.arange(3,30),[1],parameters=1440, +# tam=[15,8], plotforecasts=False,elev=45, azim=40, +# save=False,file="pictures/sonda_sfts_error_surface", intervals=False) + +from pyFTS.models.seasonal import SeasonalIndexer +from pyFTS.models import msfts +from pyFTS.common import FLR + +ix = SeasonalIndexer.DataFrameSeasonalIndexer(['day','min'],[30, 60],'glo_avg') + +fs = Grid.GridPartitionerTrimf(ix.get_data(sonda_treino),20) + +#mfts = msfts.MultiSeasonalFTS("",ix) + +#mfts.train(sonda_teste,fs) + +#print(str(mfts)) + +#[10, 508] + +flrs = FLR.generateIndexedFLRs(fs, ix, sonda_treino[110000:111450]) + +for i in flrs: #ix.get_data(sonda_treino[111430:111450]): + print(i) \ No newline at end of file