- Several bugfixes

- Issue #2 - PEP 8 compliance
  - Issue #3 - Code documentation with PEP 257 compliance
This commit is contained in:
Petrônio Cândido de Lima e Silva 2017-05-02 11:32:03 -03:00
parent 474a9d87a7
commit a4903fd932
25 changed files with 335 additions and 70 deletions

View File

@ -0,0 +1,3 @@
"""
pyFTS - A Python library for Fuzzy Time Series models
"""

View File

@ -1,12 +1,21 @@
# -*- coding: utf8 -*- # -*- coding: utf8 -*-
"""
pyFTS module for common benchmark metrics
"""
import numpy as np import numpy as np
import pandas as pd import pandas as pd
from pyFTS.common import FuzzySet,SortedCollection from pyFTS.common import FuzzySet,SortedCollection
# Autocorrelation function estimative
def acf(data, k): def acf(data, k):
"""
Autocorrelation function estimative
:param data:
:param k:
:return:
"""
mu = np.mean(data) mu = np.mean(data)
sigma = np.var(data) sigma = np.var(data)
n = len(data) n = len(data)
@ -17,22 +26,45 @@ def acf(data, k):
return 1/((n-k)*sigma)*s return 1/((n-k)*sigma)*s
# Erro quadrático médio
def rmse(targets, forecasts): def rmse(targets, forecasts):
"""
Root Mean Squared Error
:param targets:
:param forecasts:
:return:
"""
return np.sqrt(np.nanmean((targets - forecasts) ** 2)) return np.sqrt(np.nanmean((targets - forecasts) ** 2))
def rmse_interval(targets, forecasts): def rmse_interval(targets, forecasts):
"""
Root Mean Squared Error
:param targets:
:param forecasts:
:return:
"""
fmean = [np.mean(i) for i in forecasts] fmean = [np.mean(i) for i in forecasts]
return np.sqrt(np.nanmean((fmean - targets) ** 2)) return np.sqrt(np.nanmean((fmean - targets) ** 2))
# Erro Percentual médio
def mape(targets, forecasts): def mape(targets, forecasts):
"""
Mean Average Percentual Error
:param targets:
:param forecasts:
:return:
"""
return np.mean(np.abs(targets - forecasts) / targets) * 100 return np.mean(np.abs(targets - forecasts) / targets) * 100
def smape(targets, forecasts, type=2): def smape(targets, forecasts, type=2):
"""
Symmetric Mean Average Percentual Error
:param targets:
:param forecasts:
:param type:
:return:
"""
if type == 1: if type == 1:
return np.mean(np.abs(forecasts - targets) / ((forecasts + targets)/2)) return np.mean(np.abs(forecasts - targets) / ((forecasts + targets)/2))
elif type == 2: elif type == 2:
@ -46,8 +78,13 @@ def mape_interval(targets, forecasts):
return np.mean(abs(fmean - targets) / fmean) * 100 return np.mean(abs(fmean - targets) / fmean) * 100
# Theil's U Statistic
def UStatistic(targets, forecasts): def UStatistic(targets, forecasts):
"""
Theil's U Statistic
:param targets:
:param forecasts:
:return:
"""
l = len(targets) l = len(targets)
naive = [] naive = []
y = [] y = []
@ -57,8 +94,13 @@ def UStatistic(targets, forecasts):
return np.sqrt(sum(y) / sum(naive)) return np.sqrt(sum(y) / sum(naive))
# Theils Inequality Coefficient
def TheilsInequality(targets, forecasts): def TheilsInequality(targets, forecasts):
"""
Theils Inequality Coefficient
:param targets:
:param forecasts:
:return:
"""
res = targets - forecasts res = targets - forecasts
t = len(res) t = len(res)
us = np.sqrt(sum([u**2 for u in res])) us = np.sqrt(sum([u**2 for u in res]))
@ -67,8 +109,13 @@ def TheilsInequality(targets, forecasts):
return us / (ys + fs) return us / (ys + fs)
# Q Statistic for Box-Pierce test
def BoxPierceStatistic(data, h): def BoxPierceStatistic(data, h):
"""
Q Statistic for Box-Pierce test
:param data:
:param h:
:return:
"""
n = len(data) n = len(data)
s = 0 s = 0
for k in np.arange(1,h+1): for k in np.arange(1,h+1):
@ -77,8 +124,13 @@ def BoxPierceStatistic(data, h):
return n*s return n*s
# Q Statistic for LjungBox test
def BoxLjungStatistic(data, h): def BoxLjungStatistic(data, h):
"""
Q Statistic for LjungBox test
:param data:
:param h:
:return:
"""
n = len(data) n = len(data)
s = 0 s = 0
for k in np.arange(1,h+1): for k in np.arange(1,h+1):
@ -87,21 +139,21 @@ def BoxLjungStatistic(data, h):
return n*(n-2)*s return n*(n-2)*s
# Sharpness - Mean size of the intervals
def sharpness(forecasts): def sharpness(forecasts):
"""Sharpness - Mean size of the intervals"""
tmp = [i[1] - i[0] for i in forecasts] tmp = [i[1] - i[0] for i in forecasts]
return np.mean(tmp) return np.mean(tmp)
# Resolution - Standard deviation of the intervals
def resolution(forecasts): def resolution(forecasts):
"""Resolution - Standard deviation of the intervals"""
shp = sharpness(forecasts) shp = sharpness(forecasts)
tmp = [abs((i[1] - i[0]) - shp) for i in forecasts] tmp = [abs((i[1] - i[0]) - shp) for i in forecasts]
return np.mean(tmp) return np.mean(tmp)
# Percent of
def coverage(targets, forecasts): def coverage(targets, forecasts):
"""Percent of"""
preds = [] preds = []
for i in np.arange(0, len(forecasts)): for i in np.arange(0, len(forecasts)):
if targets[i] >= forecasts[i][0] and targets[i] <= forecasts[i][1]: if targets[i] >= forecasts[i][0] and targets[i] <= forecasts[i][1]:
@ -133,8 +185,8 @@ def heavyside_cdf(bins, targets):
return df return df
# Continuous Ranked Probability Score
def crps(targets, densities): def crps(targets, densities):
"""Continuous Ranked Probability Score"""
l = len(densities.columns) l = len(densities.columns)
n = len(densities.index) n = len(densities.index)
Ff = pmf_to_cdf(densities) Ff = pmf_to_cdf(densities)

View File

@ -0,0 +1,3 @@
"""
pyFTS module for benchmarking the FTS models
"""

View File

@ -7,11 +7,14 @@ from pyFTS import fts
class ARIMA(fts.FTS): class ARIMA(fts.FTS):
"""
Façade for statsmodels.tsa.arima_model
"""
def __init__(self, order, **kwargs): def __init__(self, order, **kwargs):
super(ARIMA, self).__init__(1, "ARIMA") super(ARIMA, self).__init__(1, "ARIMA")
self.name = "ARIMA" self.name = "ARIMA"
self.detail = "Auto Regressive Integrated Moving Average" self.detail = "Auto Regressive Integrated Moving Average"
self.isHighOrder = True self.is_high_order = True
self.model = None self.model = None
self.model_fit = None self.model_fit = None
self.trained_data = None self.trained_data = None
@ -19,7 +22,7 @@ class ARIMA(fts.FTS):
self.d = 0 self.d = 0
self.q = 0 self.q = 0
self.benchmark_only = True self.benchmark_only = True
self.minOrder = 1 self.min_order = 1
def train(self, data, sets, order=1, parameters=None): def train(self, data, sets, order=1, parameters=None):
if parameters is not None: if parameters is not None:

View File

@ -5,12 +5,13 @@ from pyFTS import fts
class Naive(fts.FTS): class Naive(fts.FTS):
"""Naïve Forecasting method"""
def __init__(self, order, name, **kwargs): def __init__(self, order, name, **kwargs):
super(Naive, self).__init__(1, "Naive " + name) super(Naive, self).__init__(1, "Naive " + name)
self.name = "Naïve Model" self.name = "Naïve Model"
self.detail = "Naïve Model" self.detail = "Naïve Model"
self.benchmark_only = True self.benchmark_only = True
self.isHighOrder = False self.is_high_order = False
def forecast(self, data, **kwargs): def forecast(self, data, **kwargs):
return [k for k in data] return [k for k in data]

View File

@ -8,13 +8,14 @@ from pyFTS import fts
class QuantileRegression(fts.FTS): class QuantileRegression(fts.FTS):
"""Façade for statsmodels.regression.quantile_regression"""
def __init__(self, order, **kwargs): def __init__(self, order, **kwargs):
super(QuantileRegression, self).__init__(1, "QR") super(QuantileRegression, self).__init__(1, "QR")
self.name = "QR" self.name = "QR"
self.detail = "Quantile Regression" self.detail = "Quantile Regression"
self.isHighOrder = True self.is_high_order = True
self.hasPointForecasting = True self.has_point_forecasting = True
self.hasIntervalForecasting = True self.has_interval_forecasting = True
self.benchmark_only = True self.benchmark_only = True
self.minOrder = 1 self.minOrder = 1
self.alpha = 0.5 self.alpha = 0.5

View File

@ -1,9 +1,18 @@
import numpy as np import numpy as np
from pyFTS.common import FuzzySet from pyFTS.common import FuzzySet
"""
This module implements functions for Fuzzy Logical Relationship generation
"""
class FLR(object): class FLR(object):
"""Fuzzy Logical Relationship"""
def __init__(self, LHS, RHS): def __init__(self, LHS, RHS):
"""
Creates a Fuzzy Logical Relationship
:param LHS: Left Hand Side fuzzy set
:param RHS: Right Hand Side fuzzy set
"""
self.LHS = LHS self.LHS = LHS
self.RHS = RHS self.RHS = RHS
@ -12,7 +21,14 @@ class FLR(object):
class IndexedFLR(FLR): class IndexedFLR(FLR):
"""Season Indexed Fuzzy Logical Relationship"""
def __init__(self, index, LHS, RHS): def __init__(self, index, LHS, RHS):
"""
Create a Season Indexed Fuzzy Logical Relationship
:param index: seasonal index
:param LHS: Left Hand Side fuzzy set
:param RHS: Right Hand Side fuzzy set
"""
super(IndexedFLR, self).__init__(LHS, RHS) super(IndexedFLR, self).__init__(LHS, RHS)
self.index = index self.index = index
@ -21,6 +37,11 @@ class IndexedFLR(FLR):
def generateNonRecurrentFLRs(fuzzyData): def generateNonRecurrentFLRs(fuzzyData):
"""
Create a ordered FLR set from a list of fuzzy sets without recurrence
:param fuzzyData: ordered list of fuzzy sets
:return: ordered list of FLR
"""
flrs = {} flrs = {}
for i in range(2,len(fuzzyData)): for i in range(2,len(fuzzyData)):
tmp = FLR(fuzzyData[i-1],fuzzyData[i]) tmp = FLR(fuzzyData[i-1],fuzzyData[i])
@ -30,6 +51,11 @@ def generateNonRecurrentFLRs(fuzzyData):
def generateRecurrentFLRs(fuzzyData): def generateRecurrentFLRs(fuzzyData):
"""
Create a ordered FLR set from a list of fuzzy sets with recurrence
:param fuzzyData: ordered list of fuzzy sets
:return: ordered list of FLR
"""
flrs = [] flrs = []
for i in np.arange(1,len(fuzzyData)): for i in np.arange(1,len(fuzzyData)):
flrs.append(FLR(fuzzyData[i-1],fuzzyData[i])) flrs.append(FLR(fuzzyData[i-1],fuzzyData[i]))
@ -37,6 +63,13 @@ def generateRecurrentFLRs(fuzzyData):
def generateIndexedFLRs(sets, indexer, data): def generateIndexedFLRs(sets, indexer, data):
"""
Create a season-indexed ordered FLR set from a list of fuzzy sets with recurrence
:param sets: fuzzy sets
:param indexer: seasonality indexer
:param data: original data
:return: ordered list of FLR
"""
flrs = [] flrs = []
index = indexer.get_season_of_data(data) index = indexer.get_season_of_data(data)
ndata = indexer.get_data(data) ndata = indexer.get_data(data)

View File

@ -4,7 +4,17 @@ from pyFTS.common import Membership
class FuzzySet: class FuzzySet:
"""
Fuzzy Set
"""
def __init__(self, name, mf, parameters, centroid): def __init__(self, name, mf, parameters, centroid):
"""
Create a Fuzzy Set
:param name: fuzzy set name
:param mf: membership function
:param parameters: parameters of the membership function
:param centroid: fuzzy set center of mass
"""
self.name = name self.name = name
self.mf = mf self.mf = mf
self.parameters = parameters self.parameters = parameters
@ -17,6 +27,11 @@ class FuzzySet:
self.upper = parameters[0] + parameters[1]*3 self.upper = parameters[0] + parameters[1]*3
def membership(self, x): def membership(self, x):
"""
Calculate the membership value of a given input
:param x: input value
:return: membership value of x at this fuzzy set
"""
return self.mf(x, self.parameters) return self.mf(x, self.parameters)
def __str__(self): def __str__(self):
@ -24,11 +39,23 @@ class FuzzySet:
def fuzzyInstance(inst, fuzzySets): def fuzzyInstance(inst, fuzzySets):
"""
Calculate the membership values for a data point given fuzzy sets
:param inst: data point
:param fuzzySets: list of fuzzy sets
:return: array of membership values
"""
mv = np.array([fs.membership(inst) for fs in fuzzySets]) mv = np.array([fs.membership(inst) for fs in fuzzySets])
return mv return mv
def fuzzyInstances(data, fuzzySets): def fuzzyInstances(data, fuzzySets):
"""
Calculate the membership values for a data point given fuzzy sets
:param inst: data point
:param fuzzySets: list of fuzzy sets
:return: array of membership values
"""
ret = [] ret = []
for inst in data: for inst in data:
mv = np.array([fs.membership(inst) for fs in fuzzySets]) mv = np.array([fs.membership(inst) for fs in fuzzySets])
@ -37,10 +64,22 @@ def fuzzyInstances(data, fuzzySets):
def getMaxMembershipFuzzySet(inst, fuzzySets): def getMaxMembershipFuzzySet(inst, fuzzySets):
"""
Fuzzify a data point, returning the fuzzy set with maximum membership value
:param inst: data point
:param fuzzySets: list of fuzzy sets
:return: fuzzy set with maximum membership
"""
mv = fuzzyInstance(inst, fuzzySets) mv = fuzzyInstance(inst, fuzzySets)
return fuzzySets[np.argwhere(mv == max(mv))[0, 0]] return fuzzySets[np.argwhere(mv == max(mv))[0, 0]]
def getMaxMembershipFuzzySetIndex(inst, fuzzySets): def getMaxMembershipFuzzySetIndex(inst, fuzzySets):
"""
Fuzzify a data point, returning the fuzzy set with maximum membership value
:param inst: data point
:param fuzzySets: list of fuzzy sets
:return: fuzzy set with maximum membership
"""
mv = fuzzyInstance(inst, fuzzySets) mv = fuzzyInstance(inst, fuzzySets)
return np.argwhere(mv == max(mv))[0, 0] return np.argwhere(mv == max(mv))[0, 0]

View File

@ -4,6 +4,12 @@ from pyFTS import *
def trimf(x, parameters): def trimf(x, parameters):
"""
Triangular fuzzy membership function
:param x: data point
:param parameters: a list with 3 real values
:return: the membership value of x given the parameters
"""
xx = round(x, 3) xx = round(x, 3)
if xx < parameters[0]: if xx < parameters[0]:
return 0 return 0
@ -16,6 +22,12 @@ def trimf(x, parameters):
def trapmf(x, parameters): def trapmf(x, parameters):
"""
Trapezoidal fuzzy membership function
:param x: data point
:param parameters: a list with 4 real values
:return: the membership value of x given the parameters
"""
if x < parameters[0]: if x < parameters[0]:
return 0 return 0
elif parameters[0] <= x < parameters[1]: elif parameters[0] <= x < parameters[1]:
@ -29,6 +41,12 @@ def trapmf(x, parameters):
def gaussmf(x, parameters): def gaussmf(x, parameters):
"""
Gaussian fuzzy membership function
:param x: data point
:param parameters: a list with 2 real values (mean and variance)
:return: the membership value of x given the parameters
"""
return math.exp((-(x - parameters[0])**2)/(2 * parameters[1]**2)) return math.exp((-(x - parameters[0])**2)/(2 * parameters[1]**2))
#return math.exp(-0.5 * ((x - parameters[0]) / parameters[1]) ** 2) #return math.exp(-0.5 * ((x - parameters[0]) / parameters[1]) ** 2)

View File

@ -4,6 +4,9 @@ from pyFTS import *
class Transformation(object): class Transformation(object):
"""
Data transformation used to pre and post processing of the FTS
"""
def __init__(self, parameters): def __init__(self, parameters):
self.isInversible = True self.isInversible = True
@ -21,7 +24,9 @@ class Transformation(object):
class Differential(Transformation): class Differential(Transformation):
"""
Differentiation data transform
"""
def __init__(self, parameters): def __init__(self, parameters):
super(Differential, self).__init__(parameters) super(Differential, self).__init__(parameters)
self.lag = parameters self.lag = parameters
@ -61,7 +66,9 @@ class Differential(Transformation):
class AdaptiveExpectation(Transformation): class AdaptiveExpectation(Transformation):
"""
Adaptive Expectation post processing
"""
def __init__(self, parameters): def __init__(self, parameters):
super(AdaptiveExpectation, self).__init__(parameters) super(AdaptiveExpectation, self).__init__(parameters)
self.h = parameters self.h = parameters

View File

@ -15,10 +15,10 @@ class EnsembleFTS(fts.FTS):
self.shortname = "Ensemble FTS " + name self.shortname = "Ensemble FTS " + name
self.name = "Ensemble FTS" self.name = "Ensemble FTS"
self.flrgs = {} self.flrgs = {}
self.hasPointForecasting = True self.has_point_forecasting = True
self.hasIntervalForecasting = True self.has_interval_forecasting = True
self.hasDistributionForecasting = True self.has_probability_forecasting = True
self.isHighOrder = True self.is_high_order = True
self.models = [] self.models = []
self.parameters = [] self.parameters = []
@ -40,7 +40,7 @@ class EnsembleFTS(fts.FTS):
mfts = model("") mfts = model("")
mfts.partitioner = data_train_fs mfts.partitioner = data_train_fs
if not mfts.isHighOrder: if not mfts.is_high_order:
if transformation is not None: if transformation is not None:
mfts.appendTransformation(transformation) mfts.appendTransformation(transformation)
@ -49,7 +49,7 @@ class EnsembleFTS(fts.FTS):
self.models.append(mfts) self.models.append(mfts)
else: else:
for order in np.arange(1, max_order + 1): for order in np.arange(1, max_order + 1):
if order >= mfts.minOrder: if order >= mfts.min_order:
mfts = model("") mfts = model("")
mfts.partitioner = data_train_fs mfts.partitioner = data_train_fs

76
fts.py
View File

@ -3,21 +3,31 @@ import pandas as pd
from pyFTS import tree from pyFTS import tree
from pyFTS.common import FuzzySet, SortedCollection from pyFTS.common import FuzzySet, SortedCollection
class FTS(object): class FTS(object):
"""
Fuzzy Time Series
"""
def __init__(self, order, name, **kwargs): def __init__(self, order, name, **kwargs):
"""
Create a Fuzzy Time Series model
:param order: model order
:param name: model name
:param kwargs: model specific parameters
"""
self.sets = {} self.sets = {}
self.flrgs = {} self.flrgs = {}
self.order = order self.order = order
self.shortname = name self.shortname = name
self.name = name self.name = name
self.detail = name self.detail = name
self.isHighOrder = False self.is_high_order = False
self.minOrder = 1 self.min_order = 1
self.hasSeasonality = False self.has_seasonality = False
self.hasPointForecasting = True self.has_point_forecasting = True
self.hasIntervalForecasting = False self.has_interval_forecasting = False
self.hasDistributionForecasting = False self.has_probability_forecasting = False
self.isMultivariate = False self.is_multivariate = False
self.dump = False self.dump = False
self.transformations = [] self.transformations = []
self.transformations_param = [] self.transformations_param = []
@ -28,6 +38,11 @@ class FTS(object):
self.benchmark_only = False self.benchmark_only = False
def fuzzy(self, data): def fuzzy(self, data):
"""
Fuzzify a data point
:param data: data point
:return: maximum membership fuzzy set
"""
best = {"fuzzyset": "", "membership": 0.0} best = {"fuzzyset": "", "membership": 0.0}
for f in self.sets: for f in self.sets:
@ -39,24 +54,71 @@ class FTS(object):
return best return best
def forecast(self, data, **kwargs): def forecast(self, data, **kwargs):
"""
Point forecast one step ahead
:param data: time series with minimal length to the order of the model
:param kwargs:
:return:
"""
pass pass
def forecastInterval(self, data, **kwargs): def forecastInterval(self, data, **kwargs):
"""
Interval forecast one step ahead
:param data:
:param kwargs:
:return:
"""
pass pass
def forecastDistribution(self, data, **kwargs): def forecastDistribution(self, data, **kwargs):
"""
Probabilistic forecast one step ahead
:param data:
:param kwargs:
:return:
"""
pass pass
def forecastAhead(self, data, steps, **kwargs): def forecastAhead(self, data, steps, **kwargs):
"""
Point forecast n steps ahead
:param data:
:param steps:
:param kwargs:
:return:
"""
pass pass
def forecastAheadInterval(self, data, steps, **kwargs): def forecastAheadInterval(self, data, steps, **kwargs):
"""
Interval forecast n steps ahead
:param data:
:param steps:
:param kwargs:
:return:
"""
pass pass
def forecastAheadDistribution(self, data, steps, **kwargs): def forecastAheadDistribution(self, data, steps, **kwargs):
"""
Probabilistic forecast n steps ahead
:param data:
:param steps:
:param kwargs:
:return:
"""
pass pass
def train(self, data, sets, order=1, parameters=None): def train(self, data, sets, order=1, parameters=None):
"""
:param data:
:param sets:
:param order:
:param parameters:
:return:
"""
pass pass
def getMidpoints(self, flrg): def getMidpoints(self, flrg):

View File

@ -46,7 +46,7 @@ class HighOrderFTS(fts.FTS):
self.detail = "Chen" self.detail = "Chen"
self.order = 1 self.order = 1
self.setsDict = {} self.setsDict = {}
self.isHighOrder = True self.is_high_order = True
def generateFLRG(self, flrs): def generateFLRG(self, flrs):
flrgs = {} flrgs = {}

View File

@ -4,10 +4,10 @@ from pyFTS import fts
class HighOrderFTS(fts.FTS): class HighOrderFTS(fts.FTS):
def __init__(self, order, **kwargs): def __init__(self, order, name, **kwargs):
super(HighOrderFTS, self).__init__(1, name) super(HighOrderFTS, self).__init__(1, name)
self.isHighOrder = True self.is_high_order = True
self.minOrder = 2 self.min_order = 2
self.name = "Hwang High Order FTS" self.name = "Hwang High Order FTS"
self.shortname = "Hwang" + name self.shortname = "Hwang" + name
self.detail = "Hwang" self.detail = "Hwang"

View File

@ -13,9 +13,9 @@ class IntervalFTS(hofts.HighOrderFTS):
self.name = "Interval FTS" self.name = "Interval FTS"
self.detail = "Silva, P.; Guimarães, F.; Sadaei, H. (2016)" self.detail = "Silva, P.; Guimarães, F.; Sadaei, H. (2016)"
self.flrgs = {} self.flrgs = {}
self.hasPointForecasting = False self.has_point_forecasting = False
self.hasIntervalForecasting = True self.has_point_forecasting = True
self.isHighOrder = True self.is_high_order = True
def getUpper(self, flrg): def getUpper(self, flrg):
if flrg.strLHS() in self.flrgs: if flrg.strLHS() in self.flrgs:

View File

@ -33,7 +33,7 @@ class ImprovedWeightedFLRG(object):
class ImprovedWeightedFTS(fts.FTS): class ImprovedWeightedFTS(fts.FTS):
def __init__(self, order, **kwargs): def __init__(self, order, name, **kwargs):
super(ImprovedWeightedFTS, self).__init__(1, "IWFTS " + name) super(ImprovedWeightedFTS, self).__init__(1, "IWFTS " + name)
self.name = "Improved Weighted FTS" self.name = "Improved Weighted FTS"
self.detail = "Ismail & Efendi" self.detail = "Ismail & Efendi"

View File

@ -4,6 +4,9 @@ from pyFTS import fts, sfts, chen
class ContextualSeasonalFLRG(object): class ContextualSeasonalFLRG(object):
"""
Contextual Seasonal Fuzzy Logical Relationship Group
"""
def __init__(self, seasonality): def __init__(self, seasonality):
self.season = seasonality self.season = seasonality
self.flrgs = {} self.flrgs = {}
@ -24,16 +27,19 @@ class ContextualSeasonalFLRG(object):
class ContextualMultiSeasonalFTS(sfts.SeasonalFTS): class ContextualMultiSeasonalFTS(sfts.SeasonalFTS):
def __init__(self, order, name, **kwargs): """
Contextual Multi-Seasonal Fuzzy Time Series
"""
def __init__(self, order, name, indexer, **kwargs):
super(ContextualMultiSeasonalFTS, self).__init__("CMSFTS") super(ContextualMultiSeasonalFTS, self).__init__("CMSFTS")
self.name = "Contextual Multi Seasonal FTS" self.name = "Contextual Multi Seasonal FTS"
self.shortname = "CMSFTS " + name self.shortname = "CMSFTS " + name
self.detail = "" self.detail = ""
self.seasonality = 1 self.seasonality = 1
self.hasSeasonality = True self.has_seasonality = True
self.hasPointForecasting = True self.has_point_forecasting = True
self.isHighOrder = True self.is_high_order = True
self.isMultivariate = True self.is_multivariate = True
self.indexer = indexer self.indexer = indexer
self.flrgs = {} self.flrgs = {}

View File

@ -4,7 +4,10 @@ from pyFTS import fts, sfts
class MultiSeasonalFTS(sfts.SeasonalFTS): class MultiSeasonalFTS(sfts.SeasonalFTS):
def __init__(self, order, name, **kwargs): """
Multi-Seasonal Fuzzy Time Series
"""
def __init__(self, order, name, indexer, **kwargs):
super(MultiSeasonalFTS, self).__init__("MSFTS") super(MultiSeasonalFTS, self).__init__("MSFTS")
self.name = "Multi Seasonal FTS" self.name = "Multi Seasonal FTS"
self.shortname = "MSFTS " + name self.shortname = "MSFTS " + name

View File

@ -2,6 +2,9 @@ import numpy as np
from enum import Enum from enum import Enum
class SeasonalIndexer(object): class SeasonalIndexer(object):
"""
Seasonal Indexer. Responsible to find the seasonal index of a data point inside its data set
"""
def __init__(self,num_seasons): def __init__(self,num_seasons):
self.num_seasons = num_seasons self.num_seasons = num_seasons

View File

@ -0,0 +1,3 @@
"""
Module for pyFTS Universe of Discourse partitioners.
"""

View File

@ -3,7 +3,21 @@ import numpy as np
class Partitioner(object): class Partitioner(object):
"""
Universe of Discourse partitioner. Split data on several fuzzy sets
"""
def __init__(self, name, data, npart, func=Membership.trimf, names=None, prefix="A", transformation=None): def __init__(self, name, data, npart, func=Membership.trimf, names=None, prefix="A", transformation=None):
"""
Universe of Discourse partitioner scheme. Split data on several fuzzy sets
:param name: partitioner name
:param data: original data to be partitioned
:param npart: number of partitions
:param func: membership function
:param names: list of partitions names. If None is given the partitions will be auto named with prefix
:param prefix: prefix of auto generated partition names
:param transformation: data transformation to be applied on data
"""
self.name = name self.name = name
self.partitions = npart self.partitions = npart
self.sets = [] self.sets = []
@ -31,9 +45,19 @@ class Partitioner(object):
self.sets = self.build(ndata) self.sets = self.build(ndata)
def build(self, data): def build(self, data):
"""
Perform the partitioning of the Universe of Discourse
:param data:
:return:
"""
pass pass
def plot(self, ax): def plot(self, ax):
"""
Plot the
:param ax:
:return:
"""
ax.set_title(self.name) ax.set_title(self.name)
ax.set_ylim([0, 1]) ax.set_ylim([0, 1])
ax.set_xlim([self.min, self.max]) ax.set_xlim([self.min, self.max])

View File

@ -13,31 +13,31 @@ class ProbabilisticWeightedFLRG(hofts.HighOrderFLRG):
def __init__(self, order): def __init__(self, order):
super(ProbabilisticWeightedFLRG, self).__init__(order) super(ProbabilisticWeightedFLRG, self).__init__(order)
self.RHS = {} self.RHS = {}
self.frequencyCount = 0.0 self.frequency_count = 0.0
def appendRHS(self, c): def appendRHS(self, c):
self.frequencyCount += 1.0 self.frequency_count += 1.0
if c.name in self.RHS: if c.name in self.RHS:
self.RHS[c.name] += 1.0 self.RHS[c.name] += 1.0
else: else:
self.RHS[c.name] = 1.0 self.RHS[c.name] = 1.0
def appendRHSFuzzy(self, c, mv): def appendRHSFuzzy(self, c, mv):
self.frequencyCount += mv self.frequency_count += mv
if c.name in self.RHS: if c.name in self.RHS:
self.RHS[c.name] += mv self.RHS[c.name] += mv
else: else:
self.RHS[c.name] = mv self.RHS[c.name] = mv
def get_probability(self, c): def get_probability(self, c):
return self.RHS[c] / self.frequencyCount return self.RHS[c] / self.frequency_count
def __str__(self): def __str__(self):
tmp2 = "" tmp2 = ""
for c in sorted(self.RHS): for c in sorted(self.RHS):
if len(tmp2) > 0: if len(tmp2) > 0:
tmp2 = tmp2 + ", " tmp2 = tmp2 + ", "
tmp2 = tmp2 + "(" + str(round(self.RHS[c] / self.frequencyCount, 3)) + ")" + c tmp2 = tmp2 + "(" + str(round(self.RHS[c] / self.frequency_count, 3)) + ")" + c
return self.strLHS() + " -> " + tmp2 return self.strLHS() + " -> " + tmp2
@ -48,11 +48,11 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS):
self.name = "Probabilistic FTS" self.name = "Probabilistic FTS"
self.detail = "Silva, P.; Guimarães, F.; Sadaei, H." self.detail = "Silva, P.; Guimarães, F.; Sadaei, H."
self.flrgs = {} self.flrgs = {}
self.globalFrequency = 0 self.global_frequency_count = 0
self.hasPointForecasting = True self.has_point_forecasting = True
self.hasIntervalForecasting = True self.has_interval_forecasting = True
self.hasDistributionForecasting = True self.has_probability_forecasting = True
self.isHighOrder = True self.is_high_order = True
self.auto_update = kwargs.get('update',False) self.auto_update = kwargs.get('update',False)
def train(self, data, sets, order=1,parameters=None): def train(self, data, sets, order=1,parameters=None):
@ -108,7 +108,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS):
for c, e in enumerate(_sets, start=0): for c, e in enumerate(_sets, start=0):
flrgs[flrg.strLHS()].appendRHSFuzzy(e,rhs_mv[c]*max(lhs_mv)) flrgs[flrg.strLHS()].appendRHSFuzzy(e,rhs_mv[c]*max(lhs_mv))
self.globalFrequency += max(lhs_mv) self.global_frequency_count += max(lhs_mv)
return (flrgs) return (flrgs)
@ -130,7 +130,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS):
flrgs[flrg.strLHS()].appendRHS(flrs[k-1].RHS) flrgs[flrg.strLHS()].appendRHS(flrs[k-1].RHS)
if self.dump: print("RHS: " + str(flrs[k-1])) if self.dump: print("RHS: " + str(flrs[k-1]))
self.globalFrequency += 1 self.global_frequency_count += 1
return (flrgs) return (flrgs)
def update_model(self,data): def update_model(self,data):
@ -147,7 +147,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS):
self.flrgs[flrg.strLHS()] = flrg self.flrgs[flrg.strLHS()] = flrg
self.flrgs[flrg.strLHS()].appendRHS(fzzy[self.order]) self.flrgs[flrg.strLHS()].appendRHS(fzzy[self.order])
self.globalFrequency += 1 self.global_frequency_count += 1
def add_new_PWFLGR(self, flrg): def add_new_PWFLGR(self, flrg):
if flrg.strLHS() not in self.flrgs: if flrg.strLHS() not in self.flrgs:
@ -155,11 +155,11 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS):
for fs in flrg.LHS: tmp.appendLHS(fs) for fs in flrg.LHS: tmp.appendLHS(fs)
tmp.appendRHS(flrg.LHS[-1]) tmp.appendRHS(flrg.LHS[-1])
self.flrgs[tmp.strLHS()] = tmp; self.flrgs[tmp.strLHS()] = tmp;
self.globalFrequency += 1 self.global_frequency_count += 1
def get_probability(self, flrg): def get_probability(self, flrg):
if flrg.strLHS() in self.flrgs: if flrg.strLHS() in self.flrgs:
return self.flrgs[flrg.strLHS()].frequencyCount / self.globalFrequency return self.flrgs[flrg.strLHS()].frequency_count / self.global_frequency_count
else: else:
self.add_new_PWFLGR(flrg) self.add_new_PWFLGR(flrg)
return self.get_probability(flrg) return self.get_probability(flrg)
@ -572,6 +572,6 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS):
def __str__(self): def __str__(self):
tmp = self.name + ":\n" tmp = self.name + ":\n"
for r in sorted(self.flrgs): for r in sorted(self.flrgs):
p = round(self.flrgs[r].frequencyCount / self.globalFrequency, 3) p = round(self.flrgs[r].frequencyCount / self.global_frequency_count, 3)
tmp = tmp + "(" + str(p) + ") " + str(self.flrgs[r]) + "\n" tmp = tmp + "(" + str(p) + ") " + str(self.flrgs[r]) + "\n"
return tmp return tmp

View File

@ -2,6 +2,7 @@ import numpy as np
from pyFTS.common import FuzzySet,FLR from pyFTS.common import FuzzySet,FLR
from pyFTS import fts from pyFTS import fts
class ExponentialyWeightedFLRG(object): class ExponentialyWeightedFLRG(object):
def __init__(self, LHS, c): def __init__(self, LHS, c):
self.LHS = LHS self.LHS = LHS

View File

@ -31,9 +31,9 @@ class SeasonalFTS(fts.FTS):
self.name = "Seasonal FTS" self.name = "Seasonal FTS"
self.detail = "Chen" self.detail = "Chen"
self.seasonality = 1 self.seasonality = 1
self.hasSeasonality = True self.has_seasonality = True
self.hasPointForecasting = True self.has_point_forecasting = True
self.isHighOrder = False self.is_high_order = False
def generateFLRG(self, flrs): def generateFLRG(self, flrs):
flrgs = [] flrgs = []

View File

@ -0,0 +1,3 @@
"""
Module for testing pyFTS modules and models
"""