From 04b1ffea85d17ba7b36586437bf6e1b640503a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=C3=B4nio=20C=C3=A2ndido?= Date: Fri, 6 Oct 2017 15:09:10 -0300 Subject: [PATCH] - FLRG improvements and refactorings on affected classes --- pyFTS/chen.py | 5 +-- pyFTS/flrg.py | 28 +++++++++++++ pyFTS/fts.py | 4 -- pyFTS/hofts.py | 8 +--- pyFTS/ifts.py | 20 ++++----- pyFTS/ismailefendi.py | 6 +-- pyFTS/nonstationary/flrg.py | 14 ++----- pyFTS/nonstationary/honsfts.py | 75 +++++++++++++++++++--------------- pyFTS/pwfts.py | 73 +++++++++++++++++++-------------- pyFTS/sadaei.py | 2 +- pyFTS/yu.py | 2 +- 11 files changed, 131 insertions(+), 106 deletions(-) diff --git a/pyFTS/chen.py b/pyFTS/chen.py index 385e143..e295b2b 100644 --- a/pyFTS/chen.py +++ b/pyFTS/chen.py @@ -29,8 +29,6 @@ class ConventionalFLRG(flrg.FLRG): return tmp + tmp2 - - class ConventionalFTS(fts.FTS): """Conventional Fuzzy Time Series""" def __init__(self, name, **kwargs): @@ -74,9 +72,8 @@ class ConventionalFTS(fts.FTS): ret.append(actual.centroid) else: flrg = self.flrgs[actual.name] - mp = self.getMidpoints(flrg) - ret.append(sum(mp) / len(mp)) + ret.append(flrg.get_midpoint()) ret = self.doInverseTransformations(ret, params=[data[self.order - 1:]]) diff --git a/pyFTS/flrg.py b/pyFTS/flrg.py index 10bcaf8..6bcbf16 100644 --- a/pyFTS/flrg.py +++ b/pyFTS/flrg.py @@ -1,3 +1,4 @@ +import numpy as np class FLRG(object): @@ -10,6 +11,33 @@ class FLRG(object): self.lower = None self.upper = None + def get_midpoint(self): + if self.midpoint is None: + self.midpoint = sum(self.get_midpoints())/len(self.RHS) + return self.midpoint + + def get_midpoints(self): + if isinstance(self.RHS, list): + return np.array([s.centroid for s in self.RHS]) + elif isinstance(self.RHS, dict): + return np.array([self.RHS[s].centroid for s in self.RHS.keys()]) + + def get_lower(self): + if self.lower is None: + if isinstance(self.RHS, list): + self.lower = min([rhs.lower for rhs in self.RHS]) + elif isinstance(self.RHS, dict): + self.lower = min([self.RHS[s].lower for s in self.RHS.keys()]) + return self.lower + + def get_upper(self, t): + if self.upper is None: + if isinstance(self.RHS, list): + self.upper = max([rhs.upper for rhs in self.RHS]) + elif isinstance(self.RHS, dict): + self.upper = max([self.RHS[s].upper for s in self.RHS.keys()]) + return self.upper + def __len__(self): return len(self.RHS) diff --git a/pyFTS/fts.py b/pyFTS/fts.py index 1b757c8..998c8ce 100644 --- a/pyFTS/fts.py +++ b/pyFTS/fts.py @@ -132,10 +132,6 @@ class FTS(object): """ pass - def getMidpoints(self, flrg): - ret = np.array([s.centroid for s in flrg.RHS]) - return ret - def appendTransformation(self, transformation): if transformation is not None: self.transformations.append(transformation) diff --git a/pyFTS/hofts.py b/pyFTS/hofts.py index 6f0f0d4..7a12962 100644 --- a/pyFTS/hofts.py +++ b/pyFTS/hofts.py @@ -84,10 +84,6 @@ class HighOrderFTS(fts.FTS): flrs = FLR.generateRecurrentFLRs(tmpdata) self.flrgs = self.generateFLRG(flrs) - def getMidpoints(self, flrg): - ret = np.array([self.setsDict[s].centroid for s in flrg.RHS]) - return ret - def forecast(self, data, **kwargs): ret = [] @@ -109,9 +105,7 @@ class HighOrderFTS(fts.FTS): ret.append(tmpdata[-1].centroid) else: flrg = self.flrgs[tmpflrg.strLHS()] - mp = self.getMidpoints(flrg) - - ret.append(sum(mp) / len(mp)) + ret.append(flrg.get_midpoint()) ret = self.doInverseTransformations(ret, params=[data[self.order-1:]]) diff --git a/pyFTS/ifts.py b/pyFTS/ifts.py index 0766072..d534c1b 100644 --- a/pyFTS/ifts.py +++ b/pyFTS/ifts.py @@ -23,27 +23,27 @@ class IntervalFTS(hofts.HighOrderFTS): self.has_interval_forecasting = True self.is_high_order = True - def getUpper(self, flrg): + def get_upper(self, flrg): if flrg.strLHS() in self.flrgs: tmp = self.flrgs[flrg.strLHS()] - ret = max(np.array([self.setsDict[s].upper for s in tmp.RHS])) + ret = tmp.get_upper() else: ret = flrg.LHS[-1].upper return ret - def getLower(self, flrg): + def get_lower(self, flrg): if flrg.strLHS() in self.flrgs: tmp = self.flrgs[flrg.strLHS()] - ret = min(np.array([self.setsDict[s].lower for s in tmp.RHS])) + ret = tmp.get_lower() else: ret = flrg.LHS[-1].lower return ret - def getSequenceMembership(self, data, fuzzySets): + def get_sequence_membership(self, data, fuzzySets): mb = [fuzzySets[k].membership(data[k]) for k in np.arange(0, len(data))] return mb - def buildTree(self, node, lags, level): + def build_tree(self, node, lags, level): if level >= self.order: return @@ -51,7 +51,7 @@ class IntervalFTS(hofts.HighOrderFTS): node.appendChild(tree.FLRGTreeNode(s)) for child in node.getChildren(): - self.buildTree(child, lags, level + 1) + self.build_tree(child, lags, level + 1) def forecastInterval(self, data, **kwargs): @@ -96,7 +96,7 @@ class IntervalFTS(hofts.HighOrderFTS): root = tree.FLRGTreeNode(None) - self.buildTree(root, lags, 0) + self.build_tree(root, lags, 0) # Traça os possíveis caminhos e costrói as HOFLRG's @@ -132,8 +132,8 @@ class IntervalFTS(hofts.HighOrderFTS): count = 0 for flrg in affected_flrgs: # achar o os bounds de cada FLRG, ponderados pela pertinência - up.append(affected_flrgs_memberships[count] * self.getUpper(flrg)) - lo.append(affected_flrgs_memberships[count] * self.getLower(flrg)) + up.append(affected_flrgs_memberships[count] * self.get_upper(flrg)) + lo.append(affected_flrgs_memberships[count] * self.get_lower(flrg)) count = count + 1 # gerar o intervalo diff --git a/pyFTS/ismailefendi.py b/pyFTS/ismailefendi.py index 2031105..27a49e9 100644 --- a/pyFTS/ismailefendi.py +++ b/pyFTS/ismailefendi.py @@ -70,10 +70,6 @@ class ImprovedWeightedFTS(fts.FTS): flrs = FLR.generateRecurrentFLRs(tmpdata) self.flrgs = self.generateFLRG(flrs) - def getMidpoints(self, flrg): - ret = np.array([self.setsDict[s].centroid for s in flrg.RHS]) - return ret - def forecast(self, data, **kwargs): l = 1 @@ -94,7 +90,7 @@ class ImprovedWeightedFTS(fts.FTS): ret.append(actual.centroid) else: flrg = self.flrgs[actual.name] - mp = self.getMidpoints(flrg) + mp = flrg.get_midpoints() ret.append(mp.dot(flrg.weights())) diff --git a/pyFTS/nonstationary/flrg.py b/pyFTS/nonstationary/flrg.py index c026871..48e0803 100644 --- a/pyFTS/nonstationary/flrg.py +++ b/pyFTS/nonstationary/flrg.py @@ -11,24 +11,16 @@ class NonStationaryFLRG(flrg.FLRG): def get_midpoint(self, t): if self.midpoint is None: - tmp = [] - for r in self.RHS: - tmp.append(r.get_midpoint(t)) + tmp = [r.get_midpoint(t) for r in self.RHS] self.midpoint = sum(tmp) / len(tmp) return self.midpoint def get_lower(self, t): if self.lower is None: - tmp = [] - for r in self.RHS: - tmp.append(r.get_midpoint(t)) - self.lower = min(tmp) + self.lower = min([r.get_lower(t) for r in self.RHS]) return self.lower def get_upper(self, t): if self.upper is None: - tmp = [] - for r in self.RHS: - tmp.append(r.get_midpoint(t)) - self.upper = max(tmp) + self.upper = min([r.get_upper(t) for r in self.RHS]) return self.upper \ No newline at end of file diff --git a/pyFTS/nonstationary/honsfts.py b/pyFTS/nonstationary/honsfts.py index bec087c..98be909 100644 --- a/pyFTS/nonstationary/honsfts.py +++ b/pyFTS/nonstationary/honsfts.py @@ -1,55 +1,64 @@ import numpy as np from pyFTS.common import FuzzySet, FLR from pyFTS import fts, hofts -from pyFTS.nonstationary import common +from pyFTS.nonstationary import common, flrg -class HighOrderNonStationaryFLRG(hofts.HighOrderFLRG): +class HighOrderNonStationaryFLRG(flrg.NonStationaryFLRG): """First Order NonStationary Fuzzy Logical Relationship Group""" - def __init__(self, order): - super(HighOrderNonStationaryFLRG, self).__init__(order) + def __init__(self, order, **kwargs): + super(HighOrderNonStationaryFLRG, self).__init__(order, **kwargs) - def get_midpoint(self, t): - if self.midpoint is None: - tmp = [] - for r in self.RHS: - tmp.append(r.get_midpoint(t)) - self.midpoint = sum(tmp)/len(tmp) - return self.midpoint + self.LHS = [] + self.RHS = {} + self.strlhs = "" - def get_lower(self, t): - if self.lower is None: - tmp = [] - for r in self.RHS: - tmp.append(r.get_midpoint(t)) - self.lower = min(tmp) - return self.lower + def appendRHS(self, c): + if c.name not in self.RHS: + self.RHS[c.name] = c - def get_upper(self, t): - if self.upper is None: - tmp = [] - for r in self.RHS: - tmp.append(r.get_midpoint(t)) - self.upper = max(tmp) - return self.upper + def strLHS(self): + if len(self.strlhs) == 0: + for c in self.LHS: + if len(self.strlhs) > 0: + self.strlhs += ", " + self.strlhs = self.strlhs + c.name + return self.strlhs + + def appendLHS(self, c): + self.LHS.append(c) + + def __str__(self): + tmp = "" + for c in sorted(self.RHS): + if len(tmp) > 0: + tmp = tmp + "," + tmp = tmp + c + return self.strLHS() + " -> " + tmp -class NonStationaryFTS(fts.FTS): +class HighOrderNonStationaryFTS(hofts.HighOrderFLRG): """NonStationaryFTS Fuzzy Time Series""" def __init__(self, name, **kwargs): - super(NonStationaryFTS, self).__init__(1, "NSFTS " + name, **kwargs) - self.name = "Non Stationary FTS" + super(HighOrderNonStationaryFTS, self).__init__(1, "HONSFTS " + name, **kwargs) + self.name = "High Order Non Stationary FTS" self.detail = "" self.flrgs = {} def generateFLRG(self, flrs): flrgs = {} - for flr in flrs: - if flr.LHS.name in flrgs: - flrgs[flr.LHS.name].append(flr.RHS) + l = len(flrs) + for k in np.arange(self.order + 1, l): + flrg = HighOrderNonStationaryFLRG(self.order) + + for kk in np.arange(k - self.order, k): + flrg.appendLHS(flrs[kk].LHS) + + if flrg.strLHS() in flrgs: + flrgs[flrg.strLHS()].appendRHS(flrs[k].RHS) else: - flrgs[flr.LHS.name] = NonStationaryFLRG(flr.LHS) - flrgs[flr.LHS.name].append(flr.RHS) + flrgs[flrg.strLHS()] = flrg; + flrgs[flrg.strLHS()].appendRHS(flrs[k].RHS) return (flrgs) def train(self, data, sets=None,order=1,parameters=None): diff --git a/pyFTS/pwfts.py b/pyFTS/pwfts.py index 6f65f89..3412719 100644 --- a/pyFTS/pwfts.py +++ b/pyFTS/pwfts.py @@ -15,25 +15,28 @@ class ProbabilisticWeightedFLRG(hofts.HighOrderFLRG): def __init__(self, order): super(ProbabilisticWeightedFLRG, self).__init__(order) self.RHS = {} + self.rhs_count = {} self.frequency_count = 0.0 self.Z = None def appendRHS(self, c): self.frequency_count += 1.0 if c.name in self.RHS: - self.RHS[c.name] += 1.0 + self.rhs_count[c.name] += 1.0 else: - self.RHS[c.name] = 1.0 + self.RHS[c.name] = c + self.rhs_count[c.name] = 1.0 def appendRHSFuzzy(self, c, mv): self.frequency_count += mv if c.name in self.RHS: - self.RHS[c.name] += mv + self.rhs_count[c.name] += mv else: - self.RHS[c.name] = mv + self.RHS[c.name] = c + self.rhs_count[c.name] = mv def get_RHSprobability(self, c): - return self.RHS[c] / self.frequency_count + return self.rhs_count[c] / self.frequency_count def lhs_probability(self, x, norm, uod, nbins): pk = self.frequency_count / norm @@ -44,8 +47,8 @@ class ProbabilisticWeightedFLRG(hofts.HighOrderFLRG): def rhs_conditional_probability(self, x, sets, uod, nbins): total = 0.0 - for rhs in self.RHS: - set = sets[rhs] + for rhs in self.RHS.keys(): + set = self.RHS[rhs] wi = self.get_RHSprobability(rhs) mv = set.membership(x) / set.partition_function(uod, nbins=nbins) total += wi * mv @@ -58,7 +61,7 @@ class ProbabilisticWeightedFLRG(hofts.HighOrderFLRG): mv.append(set.membership(x[count])) min_mv = np.prod(mv) - return min_mv + return min_mv def partition_function(self, uod, nbins=100): if self.Z is None: @@ -69,12 +72,24 @@ class ProbabilisticWeightedFLRG(hofts.HighOrderFLRG): return self.Z + def get_midpoint(self): + return sum(np.array([self.get_RHSprobability(s.name) * self.RHS[s].centroid + for s in self.RHS.keys()])) + + def get_upper(self): + return sum(np.array([self.get_RHSprobability(s.name) * self.RHS[s].upper + for s in self.RHS.keys()])) + + def get_lower(self): + return sum(np.array([self.get_RHSprobability(s.name) * self.RHS[s].lower + for s in self.RHS.keys()])) + def __str__(self): tmp2 = "" - for c in sorted(self.RHS): + for c in sorted(self.RHS.keys()): if len(tmp2) > 0: tmp2 = tmp2 + ", " - tmp2 = tmp2 + "(" + str(round(self.RHS[c] / self.frequency_count, 3)) + ")" + c + tmp2 = tmp2 + "(" + str(round(self.rhs_count[c] / self.frequency_count, 3)) + ")" + c return self.strLHS() + " -> " + tmp2 @@ -136,7 +151,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): root = tree.FLRGTreeNode(None) - self.buildTreeWithoutOrder(root, lags, 0) + self.build_tree_without_order(root, lags, 0) # Trace the possible paths for p in root.paths(): @@ -214,10 +229,10 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): self.add_new_PWFLGR(flrg) return self.get_flrg_global_probability(flrg) - def getMidpoints(self, flrg): + def get_midpoint(self, flrg): if flrg.strLHS() in self.flrgs: tmp = self.flrgs[flrg.strLHS()] - ret = sum(np.array([tmp.get_RHSprobability(s) * self.setsDict[s].centroid for s in tmp.RHS])) + ret = tmp.get_midpoint() #sum(np.array([tmp.get_RHSprobability(s) * self.setsDict[s].centroid for s in tmp.RHS])) else: pi = 1 / len(flrg.LHS) ret = sum(np.array([pi * s.centroid for s in flrg.LHS])) @@ -241,25 +256,25 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): ret = sum(np.array([pi * self.setsDict[s].membership(x) for s in flrg.LHS])) return ret - def getUpper(self, flrg): + def get_upper(self, flrg): if flrg.strLHS() in self.flrgs: tmp = self.flrgs[flrg.strLHS()] - ret = sum(np.array([tmp.get_RHSprobability(s) * self.setsDict[s].upper for s in tmp.RHS])) + ret = tmp.get_upper() else: pi = 1 / len(flrg.LHS) ret = sum(np.array([pi * s.upper for s in flrg.LHS])) return ret - def getLower(self, flrg): + def get_lower(self, flrg): if flrg.strLHS() in self.flrgs: tmp = self.flrgs[flrg.strLHS()] - ret = sum(np.array([tmp.get_RHSprobability(s) * self.setsDict[s].lower for s in tmp.RHS])) + ret = tmp.get_lower() else: pi = 1 / len(flrg.LHS) ret = sum(np.array([pi * s.lower for s in flrg.LHS])) return ret - def buildTreeWithoutOrder(self, node, lags, level): + def build_tree_without_order(self, node, lags, level): if level not in lags: return @@ -268,7 +283,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): node.appendChild(tree.FLRGTreeNode(s)) for child in node.getChildren(): - self.buildTreeWithoutOrder(child, lags, level + 1) + self.build_tree_without_order(child, lags, level + 1) def forecast(self, data, **kwargs): @@ -316,7 +331,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): root = tree.FLRGTreeNode(None) - self.buildTree(root, lags, 0) + self.build_tree(root, lags, 0) # Trace the possible paths and build the PFLRG's @@ -331,7 +346,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): affected_flrgs.append(flrg) # Find the general membership of FLRG - affected_flrgs_memberships.append(min(self.getSequenceMembership(subset, flrg.LHS))) + affected_flrgs_memberships.append(min(self.get_sequence_membership(subset, flrg.LHS))) else: @@ -358,7 +373,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): norm = self.get_flrg_global_probability(flrg) * affected_flrgs_memberships[count] if norm == 0: norm = self.get_flrg_global_probability(flrg) # * 0.001 - mp.append(norm * self.getMidpoints(flrg)) + mp.append(norm * self.get_midpoint(flrg)) norms.append(norm) # gerar o intervalo @@ -438,7 +453,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): root = tree.FLRGTreeNode(None) - self.buildTree(root, lags, 0) + self.build_tree(root, lags, 0) # Trace the possible paths and build the PFLRG's @@ -453,7 +468,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): affected_flrgs.append(flrg) # Find the general membership of FLRG - affected_flrgs_memberships.append(min(self.getSequenceMembership(subset, flrg.LHS))) + affected_flrgs_memberships.append(min(self.get_sequence_membership(subset, flrg.LHS))) else: @@ -480,8 +495,8 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): norm = self.get_flrg_global_probability(flrg) * affected_flrgs_memberships[count] if norm == 0: norm = self.get_flrg_global_probability(flrg) # * 0.001 - up.append(norm * self.getUpper(flrg)) - lo.append(norm * self.getLower(flrg)) + up.append(norm * self.get_upper(flrg)) + lo.append(norm * self.get_lower(flrg)) norms.append(norm) # gerar o intervalo @@ -613,7 +628,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): root = tree.FLRGTreeNode(None) - self.buildTreeWithoutOrder(root, lags, 0) + self.build_tree_without_order(root, lags, 0) # Trace the possible paths for p in root.paths(): @@ -661,7 +676,7 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): root = tree.FLRGTreeNode(None) - self.buildTreeWithoutOrder(root, lags, 0) + self.build_tree_without_order(root, lags, 0) # Trace the possible paths for p in root.paths(): @@ -683,8 +698,6 @@ class ProbabilisticWeightedFTS(ifts.IntervalFTS): return ret - - def __str__(self): tmp = self.name + ":\n" for r in sorted(self.flrgs): diff --git a/pyFTS/sadaei.py b/pyFTS/sadaei.py index 9162132..8deb8c7 100644 --- a/pyFTS/sadaei.py +++ b/pyFTS/sadaei.py @@ -92,7 +92,7 @@ class ExponentialyWeightedFTS(fts.FTS): ret.append(actual.centroid) else: flrg = self.flrgs[actual.name] - mp = self.getMidpoints(flrg) + mp = flrg.get_midpoints() ret.append(mp.dot(flrg.weights())) diff --git a/pyFTS/yu.py b/pyFTS/yu.py index 2cba7bf..ae87cff 100644 --- a/pyFTS/yu.py +++ b/pyFTS/yu.py @@ -84,7 +84,7 @@ class WeightedFTS(fts.FTS): ret.append(actual.centroid) else: flrg = self.flrgs[actual.name] - mp = self.getMidpoints(flrg) + mp = flrg.get_midpoints() ret.append(mp.dot(flrg.weights()))