[docs]defpinball(tau,target,forecast):
@@ -275,9 +275,9 @@
:return: float, distance of forecast to the tau-quantile of the target """iftarget>=forecast:
- return(target-forecast)*tau
+ returnnp.subtract(target,forecast)*tauelse:
- return(forecast-target)*(1-tau)
+ self.centroid=set.centroid
+
+
+ def__str__(self):
+ tmp=str([str(k)forkinself.sets])
+ return"{}: {}".format(self.name,tmp)
+
diff --git a/docs/build/html/_modules/pyFTS/common/Util.html b/docs/build/html/_modules/pyFTS/common/Util.html
index 97a5965..c506c4d 100644
--- a/docs/build/html/_modules/pyFTS/common/Util.html
+++ b/docs/build/html/_modules/pyFTS/common/Util.html
@@ -251,8 +251,11 @@
:param obj: object on memory :param file: file name to store the object """
- withopen(file,'wb')as_file:
- dill.dump(obj,_file)
+ try:
+ withopen(file,'wb')as_file:
+ dill.dump(obj,_file)
+ exceptExceptionasex:
+ print("File {} could not be saved due exception {}".format(file,ex))
[docs]defload_obj(file):
diff --git a/docs/build/html/_modules/pyFTS/common/fts.html b/docs/build/html/_modules/pyFTS/common/fts.html
index 3650ef7..ae79ca3 100644
--- a/docs/build/html/_modules/pyFTS/common/fts.html
+++ b/docs/build/html/_modules/pyFTS/common/fts.html
@@ -98,6 +98,8 @@
"""A string with the model name"""self.detail=kwargs.get('name',"")"""A string with the model detailed information"""
+ self.is_wrapper=False
+ """Indicates that this model is a wrapper for other(s) method(s)"""self.is_high_order=False"""A boolean value indicating if the model support orders greater than 1, default: False"""self.min_order=1
@@ -174,8 +176,9 @@
:keyword nodes: a list with the dispy cluster nodes addresses :keyword explain: try to explain, step by step, the one-step-ahead point forecasting result given the input data. :keyword generators: for multivariate methods on multi step ahead forecasting, generators is a dict where the keys
- are the variables names (except the target_variable) and the values are lambda functions that
- accept one value (the actual value of the variable) and return the next value.
+ are the dataframe columun names (except the target_variable) and the values are lambda functions that
+ accept one value (the actual value of the variable) and return the next value or trained FTS
+ models that accept the actual values and forecast new ones. :return: a numpy array with the forecasted data """
@@ -296,13 +299,11 @@
:return: a list with the forecasted values """
-
-
ifisinstance(data,np.ndarray):data=data.tolist()ret=[]
- forkinnp.arange(0,steps):
+ forkinnp.arange(0,steps):tmp=self.forecast(data[-self.max_lag:],**kwargs)ifisinstance(tmp,(list,np.ndarray)):
@@ -388,11 +389,12 @@
if'partitioner'inkwargs:self.partitioner=kwargs.pop('partitioner')
- if(self.setsisNoneorlen(self.sets)==0)andnotself.benchmark_onlyandnotself.is_multivariate:
- ifself.partitionerisnotNone:
- self.sets=self.partitioner.sets
- else:
- raiseException("Fuzzy sets were not provided for the model. Use 'sets' parameter or 'partitioner'. ")
+ ifnotself.is_wrapper:
+ if(self.setsisNoneorlen(self.sets)==0)andnotself.benchmark_onlyandnotself.is_multivariate:
+ ifself.partitionerisnotNone:
+ self.sets=self.partitioner.sets
+ else:
+ raiseException("Fuzzy sets were not provided for the model. Use 'sets' parameter or 'partitioner'. ")if'order'inkwargs:self.order=kwargs.pop('order')
@@ -600,7 +602,7 @@
forrinsorted(self.flrgs,key=lambdakey:self.flrgs[key].get_midpoint(self.partitioner.sets)):tmp="{0}{1}\n".format(tmp,str(self.flrgs[r]))else:
- forrinself.model.flrgs:
+ forrinself.flrgs:tmp="{0}{1}\n".format(tmp,str(self.flrgs[r]))returntmp
diff --git a/docs/build/html/_modules/pyFTS/data/artificial.html b/docs/build/html/_modules/pyFTS/data/artificial.html
index de1b772..9f8755f 100644
--- a/docs/build/html/_modules/pyFTS/data/artificial.html
+++ b/docs/build/html/_modules/pyFTS/data/artificial.html
@@ -79,6 +79,148 @@
importnumpyasnp
+
[docs]classSignalEmulator(object):
+ """
+ Emulate a complex signal built from several additive and non-additive components
+ """
+
+ def__init__(self,**kwargs):
+ super(SignalEmulator,self).__init__()
+
+ self.components=[]
+ """Components of the signal"""
+
+
[docs]defstationary_gaussian(self,mu,sigma,**kwargs):
+ """
+ Creates a continuous Gaussian signal with mean mu and variance sigma.
+
+ :param mu: mean
+ :param sigma: variance
+ :keyword additive: If False it cancels the previous signal and start this one, if True
+ this signal is added to the previous one
+ :keyword start: lag index to start this signal, the default value is 0
+ :keyword it: Number of iterations, the default value is 1
+ :keyword length: Number of samples generated on each iteration, the default value is 100
+ :keyword vmin: Lower bound value of generated data, the default value is None
+ :keyword vmax: Upper bound value of generated data, the default value is None
+ :return: the current SignalEmulator instance, for method chaining
+ """
+ parameters={'mu':mu,'sigma':sigma}
+ self.components.append({'dist':'gaussian','type':'constant',
+ 'parameters':parameters,'args':kwargs})
+ returnself
+
+
[docs]defincremental_gaussian(self,mu,sigma,**kwargs):
+ """
+ Creates an additive gaussian interference on a previous signal
+
+ :param mu: increment on mean
+ :param sigma: increment on variance
+ :keyword start: lag index to start this signal, the default value is 0
+ :keyword it: Number of iterations, the default value is 1
+ :keyword length: Number of samples generated on each iteration, the default value is 100
+ :keyword vmin: Lower bound value of generated data, the default value is None
+ :keyword vmax: Upper bound value of generated data, the default value is None
+ :return: the current SignalEmulator instance, for method chaining
+ """
+ parameters={'mu':mu,'sigma':sigma}
+ self.components.append({'dist':'gaussian','type':'incremental',
+ 'parameters':parameters,'args':kwargs})
+ returnself
+
+
[docs]defperiodic_gaussian(self,type,period,mu_min,sigma_min,mu_max,sigma_max,**kwargs):
+ """
+ Creates an additive periodic gaussian interference on a previous signal
+
+ :param type: 'linear' or 'sinoidal'
+ :param period: the period of recurrence
+ :param mu: increment on mean
+ :param sigma: increment on variance
+ :keyword start: lag index to start this signal, the default value is 0
+ :keyword it: Number of iterations, the default value is 1
+ :keyword length: Number of samples generated on each iteration, the default value is 100
+ :keyword vmin: Lower bound value of generated data, the default value is None
+ :keyword vmax: Upper bound value of generated data, the default value is None
+ :return: the current SignalEmulator instance, for method chaining
+ """
+ parameters={'type':type,'period':period,
+ 'mu_min':mu_min,'sigma_min':sigma_min,'mu_max':mu_max,'sigma_max':sigma_max}
+ self.components.append({'dist':'gaussian','type':'periodic',
+ 'parameters':parameters,'args':kwargs})
+ returnself
+
+
[docs]defblip(self,**kwargs):
+ """
+ Creates an outlier greater than the maximum or lower then the minimum previous values of the signal,
+ and insert it on a random location of the signal.
+
+ :return: the current SignalEmulator instance, for method chaining
+ """
+ parameters={}
+ self.components.append({'dist':'blip','type':'blip',
+ 'parameters':parameters,'args':kwargs})
+ returnself
[docs]defgenerate_gaussian_linear(mu_ini,sigma_ini,mu_inc,sigma_inc,it=100,num=10,vmin=None,vmax=None):""" Generate data sampled from Gaussian distribution, with constant or linear changing parameters
@@ -108,6 +250,88 @@
returnret
+
[docs]defgenerate_linear_periodic_gaussian(period,mu_min,sigma_min,mu_max,sigma_max,it=100,num=10,vmin=None,vmax=None):
+ """
+ Generates a periodic linear variation on mean and variance
+
+ :param period: the period of recurrence
+ :param mu_min: initial (and minimum) mean of each period
+ :param sigma_min: initial (and minimum) variance of each period
+ :param mu_max: final (and maximum) mean of each period
+ :param sigma_max: final (and maximum) variance of each period
+ :param it: Number of iterations
+ :param num: Number of samples generated on each iteration
+ :param vmin: Lower bound value of generated data
+ :param vmax: Upper bound value of generated data
+ :return: A list of it*num float values
+ """
+
+ ifperiod>it:
+ raise("The 'period' parameter must be lesser than 'it' parameter")
+
+ mu_inc=(mu_max-mu_min)/period
+ sigma_inc=(sigma_max-sigma_min)/period
+ mu=mu_min
+ sigma=sigma_min
+ ret=[]
+ signal=True
+
+ forkinnp.arange(0,it):
+ tmp=np.random.normal(mu,sigma,num)
+ ifvminisnotNone:
+ tmp=np.maximum(np.full(num,vmin),tmp)
+ ifvmaxisnotNone:
+ tmp=np.minimum(np.full(num,vmax),tmp)
+ ret.extend(tmp)
+
+ ifk%period==0:
+ signal=notsignal
+
+ mu+=(mu_incifsignalelse-mu_inc)
+ sigma+=(sigma_incifsignalelse-sigma_inc)
+
+ sigma=max(sigma,0.005)
+
+ returnret
+
+
+
[docs]defgenerate_sinoidal_periodic_gaussian(period,mu_min,sigma_min,mu_max,sigma_max,it=100,num=10,vmin=None,vmax=None):
+ """
+ Generates a periodic sinoidal variation on mean and variance
+
+ :param period: the period of recurrence
+ :param mu_min: initial (and minimum) mean of each period
+ :param sigma_min: initial (and minimum) variance of each period
+ :param mu_max: final (and maximum) mean of each period
+ :param sigma_max: final (and maximum) variance of each period
+ :param it: Number of iterations
+ :param num: Number of samples generated on each iteration
+ :param vmin: Lower bound value of generated data
+ :param vmax: Upper bound value of generated data
+ :return: A list of it*num float values
+ """
+ mu_range=mu_max-mu_min
+ sigma_range=sigma_max-sigma_min
+ mu=mu_min
+ sigma=sigma_min
+ ret=[]
+
+ forkinnp.arange(0,it):
+ tmp=np.random.normal(mu,sigma,num)
+ ifvminisnotNone:
+ tmp=np.maximum(np.full(num,vmin),tmp)
+ ifvmaxisnotNone:
+ tmp=np.minimum(np.full(num,vmax),tmp)
+ ret.extend(tmp)
+
+ mu+=mu_range*np.sin(period*k)
+ sigma+=sigma_range*np.sin(period*k)
+
+ sigma=max(sigma,0.005)
+
+ returnret
+
+
[docs]defgenerate_uniform_linear(min_ini,max_ini,min_inc,max_inc,it=100,num=10,vmin=None,vmax=None):""" Generate data sampled from Uniform distribution, with constant or linear changing bounds
@@ -138,10 +362,22 @@
[docs]defwhite_noise(n=500):
+ """
+ Simple Gaussian noise signal
+ :param n: number of samples
+ :return:
+ """returnnp.random.normal(0,1,n)
[docs]defrandom_walk(n=500,type='gaussian'):
+ """
+ Simple random walk
+
+ :param n: number of samples
+ :param type: 'gaussian' or 'uniform'
+ :return:
+ """iftype=='gaussian':tmp=generate_gaussian_linear(0,1,0,0,it=1,num=n)else:
@@ -152,6 +388,30 @@
returnret
+importnumpyasnp
+importpandasaspd
+
+frompyFTS.dataimportEnrollments,TAIEX
+frompyFTS.partitionersimportGrid,Simple
+frompyFTS.models.multivariateimportpartitionerasmv_partitioner
+frompyFTS.modelsimporthofts
+
+frompysparkimportSparkConf
+frompysparkimportSparkContext
+
+importos
+# make sure pyspark tells workers to use python3 not 2 if both are installed
+SPARK_ADDR='spark://192.168.0.110:7077'
+
+os.environ['PYSPARK_PYTHON']='/usr/bin/python3'
+os.environ['PYSPARK_DRIVER_PYTHON']='/usr/bin/python3'
+
+
[docs]classIncrementalEnsembleFTS(ensemble.EnsembleFTS):
+ """
+ Time Variant/Incremental Ensemble of FTS methods
+ """
+ def__init__(self,**kwargs):
+ super(IncrementalEnsembleFTS,self).__init__(**kwargs)
+ self.shortname="IncrementalEnsembleFTS"
+ self.name="Incremental Ensemble FTS"
+
+ self.order=kwargs.get('order',1)
+
+ self.partitioner_method=kwargs.get('partitioner_method',Grid.GridPartitioner)
+ """The partitioner method to be called when a new model is build"""
+ self.partitioner_params=kwargs.get('partitioner_params',{'npart':10})
+ """The partitioner method parameters"""
+
+ self.fts_method=kwargs.get('fts_method',hofts.WeightedHighOrderFTS)
+ """The FTS method to be called when a new model is build"""
+ self.fts_params=kwargs.get('fts_params',{})
+ """The FTS method specific parameters"""
+
+ self.window_length=kwargs.get('window_length',100)
+ """The memory window length"""
+
+ self.batch_size=kwargs.get('batch_size',10)
+ """The batch interval between each retraining"""
+
+ self.is_high_order=True
+ self.uod_clip=False
+ #self.max_lag = self.window_length + self.max_lag
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/build/html/_modules/pyFTS/models/incremental/Retrainer.html b/docs/build/html/_modules/pyFTS/models/incremental/TimeVariant.html
similarity index 94%
rename from docs/build/html/_modules/pyFTS/models/incremental/Retrainer.html
rename to docs/build/html/_modules/pyFTS/models/incremental/TimeVariant.html
index 07d37d1..529e7d9 100644
--- a/docs/build/html/_modules/pyFTS/models/incremental/Retrainer.html
+++ b/docs/build/html/_modules/pyFTS/models/incremental/TimeVariant.html
@@ -17,7 +17,7 @@
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
- pyFTS.models.incremental.Retrainer — pyFTS 1.4 documentation
+ pyFTS.models.incremental.TimeVariant — pyFTS 1.4 documentation
@@ -71,7 +71,7 @@
-
Source code for pyFTS.models.incremental.Retrainer
+
Source code for pyFTS.models.incremental.TimeVariant
"""Meta model that wraps another FTS method and continously retrain it using a data window with the most recent data"""
@@ -81,7 +81,7 @@
frompyFTS.partitionersimportGrid
-
[docs]classRetrainer(fts.FTS):""" Meta model for incremental/online learning """
@@ -112,7 +112,7 @@
self.uod_clip=Falseself.max_lag=self.window_length+self.order
-
[docs]defforecast(self,data,**kwargs):ret=[]ndata=self.apply_transformations(data)
- forindex,rowinndata.iterrows():
- flrs=self.generate_lhs_flrs(row)
+ c=0
+ forindex,rowinndata.iterrows()ifisinstance(ndata,pd.DataFrame)elseenumerate(ndata):
+ data_point=self.format_data(row)
+ flrs=self.generate_lhs_flrs(data_point)mvs=[]mps=[]forflrinflrs:flrg=mvflrg.FLRG(lhs=flr.LHS)ifflrg.get_key()notinself.flrgs:
- mvs.append(0.)
- mps.append(0.)
+ #Naïve approach is applied when no rules were found
+ ifself.target_variable.nameinflrg.LHS:
+ fs=flrg.LHS[self.target_variable.name]
+ fset=self.target_variable.partitioner.sets[fs]
+ mp=fset.centroid
+ mv=fset.membership(data_point[self.target_variable.name])
+ mvs.append(mv)
+ mps.append(mp)
+ else:
+ mvs.append(0.)
+ mps.append(0.)else:
- mvs.append(self.flrgs[flrg.get_key()].get_membership(self.format_data(row),self.explanatory_variables))
+ mvs.append(self.flrgs[flrg.get_key()].get_membership(data_point,self.explanatory_variables))mps.append(self.flrgs[flrg.get_key()].get_midpoint(self.target_variable.partitioner.sets))mv=np.array(mvs)
@@ -211,9 +236,10 @@
ifgeneratorsisNone:raiseException('You must provide parameter \'generators\'! generators is a dict where the keys'+
- ' are the variables names (except the target_variable) and the values are '+
+ ' are the dataframe column names (except the target_variable) and the values are '+'lambda functions that accept one value (the actual value of the variable) '
- ' and return the next value.')
+ ' and return the next value or trained FTS models that accept the actual values and '
+ 'forecast new ones.')ndata=self.apply_transformations(data)
@@ -228,13 +254,20 @@
ret.append(tmp)
- last_data_point=sample.loc[sample.index[-1]]
-
new_data_point={}
- forvarinself.explanatory_variables:
- ifvar.name!=self.target_variable.name:
- new_data_point[var.data_label]=generators[var.name](last_data_point[var.data_label])
+ fordata_labelingenerators.keys():
+ ifdata_label!=self.target_variable.data_label:
+ ifisinstance(generators[data_label],LambdaType):
+ last_data_point=ndata.loc[sample.index[-1]]
+ new_data_point[data_label]=generators[data_label](last_data_point[data_label])
+ elifisinstance(generators[data_label],fts.FTS):
+ model=generators[data_label]
+ last_data_point=ndata.loc[[sample.index[-model.order]]]
+ ifnotmodel.is_multivariate:
+ last_data_point=last_data_point[data_label].values
+
+ new_data_point[data_label]=model.forecast(last_data_point)[0]new_data_point[self.target_variable.data_label]=tmp
diff --git a/docs/build/html/_modules/pyFTS/models/multivariate/variable.html b/docs/build/html/_modules/pyFTS/models/multivariate/variable.html
index 6a58361..1a4f2c5 100644
--- a/docs/build/html/_modules/pyFTS/models/multivariate/variable.html
+++ b/docs/build/html/_modules/pyFTS/models/multivariate/variable.html
@@ -104,9 +104,13 @@
self.mask=kwargs.get('mask',None)"""The mask for format the data column on Pandas Dataframe"""self.transformation=kwargs.get('transformation',None)
+ """Pre processing transformation for the variable"""self.transformation_params=kwargs.get('transformation_params',None)self.partitioner=None
+ """UoD partitioner for the variable data"""self.alpha_cut=kwargs.get('alpha_cut',0.0)
+ """Minimal membership value to be considered on fuzzyfication process"""
+
ifkwargs.get('data',None)isnotNone:self.build(**kwargs)
diff --git a/docs/build/html/_modules/pyFTS/models/seasonal/common.html b/docs/build/html/_modules/pyFTS/models/seasonal/common.html
index af960ab..13ba11d 100644
--- a/docs/build/html/_modules/pyFTS/models/seasonal/common.html
+++ b/docs/build/html/_modules/pyFTS/models/seasonal/common.html
@@ -77,12 +77,18 @@
fromenumimportEnumfrompyFTS.commonimportFuzzySet,MembershipfrompyFTS.partitionersimportpartitioner,Grid
-fromdatetimeimportdateasdt
-
+fromdatetimeimportdateasdt,datetimeasdtm
[docs]classDateTime(Enum):
+ """
+ Data and Time granularity for time granularity and seasonality identification
+ """year=1
+ half=2# six months
+ third=3# four months
+ quarter=4# three months
+ sixth=6# two monthsmonth=12day_of_month=30day_of_year=364
@@ -104,11 +110,15 @@
second_of_day=86400
@@ -1907,8 +1913,9 @@ needed to forecast a single step ahead
nodes – a list with the dispy cluster nodes addresses
explain – try to explain, step by step, the one-step-ahead point forecasting result given the input data.
generators – for multivariate methods on multi step ahead forecasting, generators is a dict where the keys
-are the variables names (except the target_variable) and the values are lambda functions that
-accept one value (the actual value of the variable) and return the next value.
+are the dataframe columun names (except the target_variable) and the values are lambda functions that
+accept one value (the actual value of the variable) and return the next value or trained FTS
+models that accept the actual values and forecast new ones.