diff --git a/pyFTS/chen.py b/pyFTS/chen.py index f0ec0c2..ce0ad0c 100644 --- a/pyFTS/chen.py +++ b/pyFTS/chen.py @@ -14,6 +14,9 @@ class ConventionalFLRG(object): def __init__(self, LHS): self.LHS = LHS self.RHS = set() + self.midpoint = None + self.lower = None + self.upper = None def append(self, c): self.RHS.add(c) diff --git a/pyFTS/common/FLR.py b/pyFTS/common/FLR.py index aeec3a3..86a12ff 100644 --- a/pyFTS/common/FLR.py +++ b/pyFTS/common/FLR.py @@ -36,32 +36,40 @@ class IndexedFLR(FLR): return str(self.index) + ": "+ self.LHS.name + " -> " + self.RHS.name -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 = {} - for i in range(2,len(fuzzyData)): - tmp = FLR(fuzzyData[i-1],fuzzyData[i]) - flrs[str(tmp)] = tmp - ret = [value for key, value in flrs.items()] - return ret - - 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 + :return: ordered list of FLR """ flrs = [] for i in np.arange(1,len(fuzzyData)): - flrs.append(FLR(fuzzyData[i-1],fuzzyData[i])) + lhs = fuzzyData[i - 1] + rhs = fuzzyData[i] + if isinstance(lhs, list) and isinstance(rhs, list): + for l in lhs: + for r in rhs: + tmp = FLR(l, r) + flrs.append(tmp) + else: + tmp = FLR.FLR(lhs,rhs) + flrs.append(tmp) return flrs +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 = generateRecurrentFLRs(fuzzyData) + tmp = {} + for flr in flrs: tmp[str(flr)] = flr + ret = [value for key, value in tmp.items()] + return ret + + def generateIndexedFLRs(sets, indexer, data, transformation=None): """ Create a season-indexed ordered FLR set from a list of fuzzy sets with recurrence diff --git a/pyFTS/nonstationary/common.py b/pyFTS/nonstationary/common.py index 07bb7b0..510ddd3 100644 --- a/pyFTS/nonstationary/common.py +++ b/pyFTS/nonstationary/common.py @@ -7,7 +7,7 @@ IEEE Transactions on Fuzzy Systems, v. 16, n. 4, p. 1072-1086, 2008. import numpy as np from pyFTS import * -from pyFTS.common import FuzzySet as FS, Membership +from pyFTS.common import FuzzySet as FS, Membership, FLR from pyFTS.partitioners import partitioner from pyFTS.nonstationary import perturbation @@ -279,3 +279,30 @@ class PolynomialNonStationaryPartitioner(partitioner.Partitioner): def build(self, data): pass + +def fuzzify(inst, t, fuzzySets): + """ + Calculate the membership values for a data point given nonstationary fuzzy sets + :param inst: data points + :param t: time displacement of the instance + :param fuzzySets: list of fuzzy sets + :return: array of membership values + """ + ret = [] + if not isinstance(inst, list): + inst = [inst] + for t, i in enumerate(inst): + mv = np.array([fs.membership(i, t) for fs in fuzzySets]) + ret.append(mv) + return ret + + +def fuzzySeries(data, fuzzySets): + fts = [] + for t, i in enumerate(data): + mv = np.array([fs.membership(i, t) for fs in fuzzySets]) + ix = np.ravel(np.argwhere(mv > 0.0)) + sets = [fuzzySets[i] for i in ix] + fts.append(sets) + return fts + diff --git a/pyFTS/nonstationary/nsfts.py b/pyFTS/nonstationary/nsfts.py index 32f03bf..bb2d39c 100644 --- a/pyFTS/nonstationary/nsfts.py +++ b/pyFTS/nonstationary/nsfts.py @@ -1,12 +1,124 @@ import numpy as np from pyFTS.common import FuzzySet, FLR -from pyFTS import fts, sfts +from pyFTS import fts, chen +from pyFTS.nonstationary import common -class NonStationaryFTS(sfts.SeasonalFTS): +class NonStationaryFLRG(chen.ConventionalFLRG): + """First Order NonStationary Fuzzy Logical Relationship Group""" + def __init__(self, LHS): + super(NonStationaryFLRG, self).__init__(LHS) + + 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 + + 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 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 + + +class NonStationaryFTS(fts.FTS): """NonStationaryFTS Fuzzy Time Series""" def __init__(self, name, **kwargs): super(NonStationaryFTS, self).__init__(1, "NSFTS " + name, **kwargs) self.name = "Non Stationary FTS" self.detail = "" - self.flrgs = {} \ No newline at end of file + self.flrgs = {} + + def generateFLRG(self, flrs): + flrgs = {} + for flr in flrs: + if flr.LHS.name in flrgs: + flrgs[flr.LHS.name].append(flr.RHS) + else: + flrgs[flr.LHS.name] = NonStationaryFLRG(flr.LHS) + flrgs[flr.LHS.name].append(flr.RHS) + return (flrgs) + + def train(self, data, sets=None,order=1,parameters=None): + + if sets is not None: + self.sets = sets + else: + self.sets = self.partitioner.sets + + ndata = self.doTransformations(data) + tmpdata = common.fuzzySeries(ndata, self.sets) + flrs = FLR.generateNonRecurrentFLRs(tmpdata) + self.flrgs = self.generateFLRG(flrs) + + def forecast(self, data, **kwargs): + + time_displacement = kwargs.get("time_displacement",0) + + ndata = np.array(self.doTransformations(data)) + + l = len(ndata) + + ret = [] + + for k in np.arange(0, l): + + tdisp = k + time_displacement + + affected_sets = [ [set, set.membership(ndata[k], tdisp)] + for set in self.sets if set.membership(ndata[k], tdisp) > 0.0] + + tmp = [] + for aset in affected_sets: + if aset[0] in self.flrgs: + tmp.append(self.flrgs[aset[0].name].get_midpoint(tdisp) * aset[1]) + else: + tmp.append(aset[0].get_midpoint(tdisp) * aset[1]) + + ret.append(sum(tmp)) + + ret = self.doInverseTransformations(ret, params=[data[self.order - 1:]]) + + return ret + + def forecastInterval(self, data, **kwargs): + + time_displacement = kwargs.get("time_displacement",0) + + ndata = np.array(self.doTransformations(data)) + + l = len(ndata) + + ret = [] + + for k in np.arange(0, l): + + tdisp = k + time_displacement + + affected_sets = [ [set.name, set.membership(ndata[k], tdisp)] + for set in self.sets if set.membership(ndata[k], tdisp) > 0.0] + + upper = [] + lower = [] + for aset in affected_sets: + lower.append(self.flrgs[aset[0]].get_lower(tdisp) * aset[1]) + upper.append(self.flrgs[aset[0]].get_upper(tdisp) * aset[1]) + + ret.append([sum(lower), sum(upper)]) + + ret = self.doInverseTransformations(ret, params=[data[self.order - 1:]]) + + return ret \ No newline at end of file diff --git a/pyFTS/tests/nonstationary.py b/pyFTS/tests/nonstationary.py index 9628b7f..8022803 100644 --- a/pyFTS/tests/nonstationary.py +++ b/pyFTS/tests/nonstationary.py @@ -1,7 +1,8 @@ import numpy as np from pyFTS.common import Membership -from pyFTS.nonstationary import common,perturbation,util +from pyFTS.nonstationary import common,perturbation,util,nsfts from pyFTS.partitioners import Grid +import matplotlib.pyplot as plt def generate_heteroskedastic_linear(mu_ini, sigma_ini, mu_inc, sigma_inc, it=10, num=35): @@ -17,22 +18,26 @@ def generate_heteroskedastic_linear(mu_ini, sigma_ini, mu_inc, sigma_inc, it=10, lmv1 = generate_heteroskedastic_linear(1,0.1,1,0.3) - - ns = 5 #number of fuzzy sets ts = 200 train = lmv1[:ts] +test = lmv1[ts:] w = 25 deg = 4 +fig, axes = plt.subplots(nrows=1, ncols=1, figsize=[10,5]) tmp_fs = Grid.GridPartitioner(train[:35], 10) fs = common.PolynomialNonStationaryPartitioner(train, tmp_fs, window_size=35, degree=1) -uod = np.arange(0, 2, step=0.02) +nsfts1 = nsfts.NonStationaryFTS("", partitioner=fs) -util.plot_sets(uod, fs.sets,tam=[15, 5], start=0, end=10) +nsfts1.train(train[:35]) -for set in fs.sets: - print(set) +tmp = nsfts1.forecast(test, time_displacement=200) + +axes.plot(test) +axes.plot(tmp) + +print(tmp)