- Seasonal partitioner

This commit is contained in:
Petrônio Cândido 2018-02-28 13:45:55 -03:00
parent 7a2dd7e54c
commit 1d583e8b0a
6 changed files with 240 additions and 44 deletions

View File

@ -11,14 +11,19 @@ class FuzzySet(FuzzySet.FuzzySet):
"""
Composite Fuzzy Set
"""
def __init__(self, name):
def __init__(self, name, superset=False):
"""
Create an empty composite fuzzy set
:param name: fuzzy set name
"""
super(FuzzySet, self).__init__(self, name=name, mf=None, parameters=None, centroid=None)
self.mf = []
self.parameters = []
super(FuzzySet, self).__init__(self, name, None, None, None, type='composite')
self.superset = superset
if self.superset:
self.sets = []
else:
self.mf = []
self.parameters = []
def membership(self, x):
"""
@ -26,7 +31,10 @@ class FuzzySet(FuzzySet.FuzzySet):
:param x: input value
:return: membership value of x at this fuzzy set
"""
return min([self.mf[ct](x, self.parameters[ct]) for ct in np.arange(0, len(self.mf))])
if self.superset:
return max([s.membership(x) for s in self.sets])
else:
return min([self.mf[ct](x, self.parameters[ct]) for ct in np.arange(0, len(self.mf))])
def append(self, mf, parameters):
"""
@ -37,3 +45,12 @@ class FuzzySet(FuzzySet.FuzzySet):
"""
self.mf.append(mf)
self.parameters.append(parameters)
def append_set(self, set):
"""
Adds a new function to composition
:param mf:
:param parameters:
:return:
"""
self.sets.append(set)

View File

@ -7,7 +7,7 @@ class FuzzySet(object):
"""
Fuzzy Set
"""
def __init__(self, name, mf, parameters, centroid):
def __init__(self, name, mf, parameters, centroid, alpha=1.0, type='common'):
"""
Create a Fuzzy Set
:param name: fuzzy set name
@ -19,6 +19,8 @@ class FuzzySet(object):
self.mf = mf
self.parameters = parameters
self.centroid = centroid
self.alpha = alpha
self.type = type
":param Z: Partition function in respect to the membership function"
self.Z = None
if self.mf == Membership.trimf:
@ -35,7 +37,7 @@ class FuzzySet(object):
: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) * self.alpha
def partition_function(self,uod=None, nbins=100):
"""

View File

@ -7,13 +7,25 @@ from pyFTS.partitioners import partitioner, Grid
class DateTime(Enum):
year = 1
month = 2
day_of_month = 3
day_of_year = 4
day_of_week = 5
month = 12
day_of_month = 30
day_of_year = 364
day_of_week = 7
hour = 6
minute = 7
second = 8
hour_of_day = 24
hour_of_week = 168
hour_of_month = 744
hour_of_year = 8736
minute_of_hour = 60
minute_of_day = 1440
minute_of_week = 10080
minute_of_month = 44640
minute_of_year = 524160
second_of_minute = 60.00001
second_of_hour = 3600
second_of_day = 86400
def strip_datepart(self, date, date_part):
@ -27,12 +39,45 @@ def strip_datepart(self, date, date_part):
tmp = date.day
elif date_part == DateTime.day_of_week:
tmp = date.weekday()
elif date_part == DateTime.hour:
elif date_part == DateTime.hour or date_part == DateTime.hour_of_day:
tmp = date.hour
elif date_part == DateTime.minute:
elif date_part == DateTime.hour_of_week:
wk = (date.weekday()-1) * 24
tmp = date.hour + wk
elif date_part == DateTime.hour_of_month:
wk = (date.day-1) * 24
tmp = date.hour + wk
elif date_part == DateTime.hour_of_year:
wk = (date.timetuple().tm_yday-1) * 24
tmp = date.hour + wk
elif date_part == DateTime.minute or date_part == DateTime.minute_of_hour:
tmp = date.minute
elif date_part == DateTime.second:
elif date_part == DateTime.minute_of_day:
wk = date.hour * 60
tmp = date.minute + wk
elif date_part == DateTime.minute_of_week:
wk1 = (date.weekday()-1) * 1440 #24 * 60
wk2 = date.hour * 60
tmp = date.minute + wk1 + wk2
elif date_part == DateTime.minute_of_month:
wk1 = (date.day - 1) * 1440 #24 * 60
wk2 = date.hour * 60
tmp = date.minute + wk1 + wk2
elif date_part == DateTime.minute_of_year:
wk1 = (date.timetuple().tm_yday - 1) * 1440 #24 * 60
wk2 = date.hour * 60
tmp = date.minute + wk1 + wk2
elif date_part == DateTime.second or date_part == DateTime.second_of_minute:
tmp = date.second
elif date_part == DateTime.second_of_hour:
wk1 = date.minute * 60
tmp = date.second + wk1
elif date_part == DateTime.second_of_day:
wk1 = date.hour * 3600 #60 * 60
wk2 = date.minute * 60
tmp = date.second + wk1 + wk2
else:
raise Exception("Unknown DateTime value!")
return tmp
@ -42,8 +87,8 @@ class FuzzySet(FuzzySet.FuzzySet):
Temporal/Seasonal Fuzzy Set
"""
def __init__(self, datepart, name, mf, parameters, centroid):
super(FuzzySet, self).__init__(name, mf, parameters, centroid)
def __init__(self, datepart, name, mf, parameters, centroid, alpha=1.0):
super(FuzzySet, self).__init__(name, mf, parameters, centroid, alpha)
self.datepart = datepart
def membership(self, x):

View File

@ -0,0 +1,101 @@
from pyFTS.common import Membership
from pyFTS.common.Composite import FuzzySet as Composite
from pyFTS.partitioners import partitioner, Grid
from pyFTS.models.seasonal.common import DateTime, FuzzySet, strip_datepart
import numpy as np
import matplotlib.pylab as plt
class TimeGridPartitioner(partitioner.Partitioner):
"""Even Length DateTime Grid Partitioner"""
def __init__(self, data, npart, season, func=Membership.trimf, names=None):
"""
Even Length Grid Partitioner
:param data: Training data of which the universe of discourse will be extracted. The universe of discourse is the open interval between the minimum and maximum values of the training data.
:param npart: The number of universe of discourse partitions, i.e., the number of fuzzy sets that will be created
:param func: Fuzzy membership function (pyFTS.common.Membership)
"""
super(TimeGridPartitioner, self).__init__("TimeGrid", data, npart, func=func, names=names, transformation=None,
indexer=None, preprocess=False)
self.season = season
if self.season == DateTime.year:
ndata = [strip_datepart(k, season) for k in data]
self.min = min(ndata)
self.max = max(ndata)
else:
tmp = (self.season.value / self.partitions) / 2
self.min = tmp
self.max = self.season.value + tmp
self.sets = self.build(None)
def build(self, data):
sets = []
if self.season == DateTime.year:
dlen = (self.max - self.min)
partlen = dlen / self.partitions
else:
partlen = self.season.value / self.partitions
pl2 = partlen / 2
count = 0
for c in np.arange(self.min, self.max, partlen):
set_name = self.prefix + str(count) if self.setnames is None else self.setnames[count]
if self.membership_function == Membership.trimf:
if c == self.min:
tmp = Composite(set_name, superset=True)
tmp.append_set(FuzzySet(self.season, set_name, Membership.trimf,
[self.season.value - pl2, self.season.value,
self.season.value + 0.0000001], self.season.value, alpha=.5))
tmp.append_set(FuzzySet(self.season, set_name, Membership.trimf,
[c - partlen, c, c + partlen], c))
tmp.centroid = c
sets.append(tmp)
else:
sets.append(FuzzySet(self.season, set_name, Membership.trimf,
[c - partlen, c, c + partlen], c))
elif self.membership_function == Membership.gaussmf:
sets.append(FuzzySet(self.season, set_name, Membership.gaussmf, [c, partlen / 3], c))
elif self.membership_function == Membership.trapmf:
q = partlen / 4
if c == self.min:
tmp = Composite(set_name, superset=True)
tmp.append_set(FuzzySet(self.season, set_name, Membership.trimf,
[self.season.value - pl2, self.season.value,
self.season.value + 0.0000001], 0))
tmp.append_set(FuzzySet(self.season, set_name, Membership.trapmf,
[c - partlen, c - q, c + q, c + partlen], c))
tmp.centroid = c
sets.append(tmp)
else:
sets.append(FuzzySet(self.season, set_name, Membership.trapmf,
[c - partlen, c - q, c + q, c + partlen], c))
count += 1
self.min = 0
return sets
def plot(self, ax):
"""
Plot the
:param ax:
:return:
"""
ax.set_title(self.name)
ax.set_ylim([0, 1])
ax.set_xlim([0, self.season.value])
ticks = []
x = []
for s in self.sets:
if s.type == 'common':
self.plot_set(ax, s)
elif s.type == 'composite':
for ss in s.sets:
self.plot_set(ax, ss)
# ticks.append(str(round(s.centroid, 0)) + '\n' + s.name)
# x.append(s.centroid)
# plt.xticks(x, ticks)

View File

@ -8,7 +8,8 @@ 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, indexer=None):
def __init__(self, name, data, npart, func=Membership.trimf, names=None, prefix="A",
transformation=None, indexer=None, preprocess=True):
"""
Universe of Discourse partitioner scheme. Split data on several fuzzy sets
:param name: partitioner name
@ -28,31 +29,33 @@ class Partitioner(object):
self.transformation = transformation
self.indexer = indexer
if self.indexer is not None:
ndata = self.indexer.get_data(data)
else:
ndata = data
if preprocess:
if transformation is not None:
ndata = transformation.apply(ndata)
else:
ndata = data
if self.indexer is not None:
ndata = self.indexer.get_data(data)
else:
ndata = data
_min = min(ndata)
if _min < 0:
self.min = _min * 1.1
else:
self.min = _min * 0.9
if transformation is not None:
ndata = transformation.apply(ndata)
else:
ndata = data
_max = max(ndata)
if _max > 0:
self.max = _max * 1.1
else:
self.max = _max * 0.9
_min = min(ndata)
if _min < 0:
self.min = _min * 1.1
else:
self.min = _min * 0.9
self.sets = self.build(ndata)
_max = max(ndata)
if _max > 0:
self.max = _max * 1.1
else:
self.max = _max * 0.9
del(ndata)
self.sets = self.build(ndata)
del(ndata)
def build(self, data):
"""
@ -74,16 +77,25 @@ class Partitioner(object):
ticks = []
x = []
for s in self.sets:
if s.mf == Membership.trimf:
ax.plot([s.parameters[0], s.parameters[1], s.parameters[2]], [0, 1, 0])
elif s.mf == Membership.gaussmf:
tmpx = [kk for kk in np.arange(s.lower, s.upper)]
tmpy = [s.membership(kk) for kk in np.arange(s.lower, s.upper)]
ax.plot(tmpx, tmpy)
if s.type == 'common':
self.plot_set(ax, s)
elif s.type == 'composite':
for ss in s.sets:
self.plot_set(ax, ss)
ticks.append(str(round(s.centroid,0))+'\n'+s.name)
x.append(s.centroid)
plt.xticks(x,ticks)
def plot_set(self, ax, s):
if s.mf == Membership.trimf:
ax.plot([s.parameters[0], s.parameters[1], s.parameters[2]], [0, s.alpha, 0])
elif s.mf == Membership.gaussmf:
tmpx = [kk for kk in np.arange(s.lower, s.upper)]
tmpy = [s.membership(kk) for kk in np.arange(s.lower, s.upper)]
ax.plot(tmpx, tmpy)
elif s.mf == Membership.trapmf:
ax.plot(s.parameters, [0, s.alpha, s.alpha, 0])
def __str__(self):
tmp = self.name + ":\n"

19
pyFTS/tests/seasonal.py Normal file
View File

@ -0,0 +1,19 @@
import matplotlib.pylab as plt
from pyFTS.models.seasonal import partitioner, common
from pyFTS.partitioners import Util
from pyFTS.common import Membership
#fs = partitioner.TimeGridPartitioner(None, 12, common.DateTime.day_of_year, func=Membership.trapmf,
# names=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'])
#fs = partitioner.TimeGridPartitioner(None, 24, common.DateTime.minute_of_day, func=Membership.trapmf)
fs = partitioner.TimeGridPartitioner(None, 7, common.DateTime.hour_of_week, func=Membership.trapmf)
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=[6, 8])
fs.plot(ax)
plt.show()