- Seasonal partitioner
This commit is contained in:
parent
7a2dd7e54c
commit
1d583e8b0a
@ -11,14 +11,19 @@ class FuzzySet(FuzzySet.FuzzySet):
|
|||||||
"""
|
"""
|
||||||
Composite Fuzzy Set
|
Composite Fuzzy Set
|
||||||
"""
|
"""
|
||||||
def __init__(self, name):
|
def __init__(self, name, superset=False):
|
||||||
"""
|
"""
|
||||||
Create an empty composite fuzzy set
|
Create an empty composite fuzzy set
|
||||||
:param name: fuzzy set name
|
:param name: fuzzy set name
|
||||||
"""
|
"""
|
||||||
super(FuzzySet, self).__init__(self, name=name, mf=None, parameters=None, centroid=None)
|
super(FuzzySet, self).__init__(self, name, None, None, None, type='composite')
|
||||||
self.mf = []
|
self.superset = superset
|
||||||
self.parameters = []
|
if self.superset:
|
||||||
|
self.sets = []
|
||||||
|
else:
|
||||||
|
self.mf = []
|
||||||
|
self.parameters = []
|
||||||
|
|
||||||
|
|
||||||
def membership(self, x):
|
def membership(self, x):
|
||||||
"""
|
"""
|
||||||
@ -26,7 +31,10 @@ class FuzzySet(FuzzySet.FuzzySet):
|
|||||||
:param x: input value
|
:param x: input value
|
||||||
:return: membership value of x at this fuzzy set
|
: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):
|
def append(self, mf, parameters):
|
||||||
"""
|
"""
|
||||||
@ -37,3 +45,12 @@ class FuzzySet(FuzzySet.FuzzySet):
|
|||||||
"""
|
"""
|
||||||
self.mf.append(mf)
|
self.mf.append(mf)
|
||||||
self.parameters.append(parameters)
|
self.parameters.append(parameters)
|
||||||
|
|
||||||
|
def append_set(self, set):
|
||||||
|
"""
|
||||||
|
Adds a new function to composition
|
||||||
|
:param mf:
|
||||||
|
:param parameters:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
self.sets.append(set)
|
@ -7,7 +7,7 @@ class FuzzySet(object):
|
|||||||
"""
|
"""
|
||||||
Fuzzy Set
|
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
|
Create a Fuzzy Set
|
||||||
:param name: fuzzy set name
|
:param name: fuzzy set name
|
||||||
@ -19,6 +19,8 @@ class FuzzySet(object):
|
|||||||
self.mf = mf
|
self.mf = mf
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
self.centroid = centroid
|
self.centroid = centroid
|
||||||
|
self.alpha = alpha
|
||||||
|
self.type = type
|
||||||
":param Z: Partition function in respect to the membership function"
|
":param Z: Partition function in respect to the membership function"
|
||||||
self.Z = None
|
self.Z = None
|
||||||
if self.mf == Membership.trimf:
|
if self.mf == Membership.trimf:
|
||||||
@ -35,7 +37,7 @@ class FuzzySet(object):
|
|||||||
:param x: input value
|
:param x: input value
|
||||||
:return: membership value of x at this fuzzy set
|
: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):
|
def partition_function(self,uod=None, nbins=100):
|
||||||
"""
|
"""
|
||||||
|
@ -7,13 +7,25 @@ from pyFTS.partitioners import partitioner, Grid
|
|||||||
|
|
||||||
class DateTime(Enum):
|
class DateTime(Enum):
|
||||||
year = 1
|
year = 1
|
||||||
month = 2
|
month = 12
|
||||||
day_of_month = 3
|
day_of_month = 30
|
||||||
day_of_year = 4
|
day_of_year = 364
|
||||||
day_of_week = 5
|
day_of_week = 7
|
||||||
hour = 6
|
hour = 6
|
||||||
minute = 7
|
minute = 7
|
||||||
second = 8
|
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):
|
def strip_datepart(self, date, date_part):
|
||||||
@ -27,12 +39,45 @@ def strip_datepart(self, date, date_part):
|
|||||||
tmp = date.day
|
tmp = date.day
|
||||||
elif date_part == DateTime.day_of_week:
|
elif date_part == DateTime.day_of_week:
|
||||||
tmp = date.weekday()
|
tmp = date.weekday()
|
||||||
elif date_part == DateTime.hour:
|
elif date_part == DateTime.hour or date_part == DateTime.hour_of_day:
|
||||||
tmp = date.hour
|
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
|
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
|
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
|
return tmp
|
||||||
|
|
||||||
@ -42,8 +87,8 @@ class FuzzySet(FuzzySet.FuzzySet):
|
|||||||
Temporal/Seasonal Fuzzy Set
|
Temporal/Seasonal Fuzzy Set
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, datepart, name, mf, parameters, centroid):
|
def __init__(self, datepart, name, mf, parameters, centroid, alpha=1.0):
|
||||||
super(FuzzySet, self).__init__(name, mf, parameters, centroid)
|
super(FuzzySet, self).__init__(name, mf, parameters, centroid, alpha)
|
||||||
self.datepart = datepart
|
self.datepart = datepart
|
||||||
|
|
||||||
def membership(self, x):
|
def membership(self, x):
|
||||||
|
101
pyFTS/models/seasonal/partitioner.py
Normal file
101
pyFTS/models/seasonal/partitioner.py
Normal 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)
|
@ -8,7 +8,8 @@ class Partitioner(object):
|
|||||||
Universe of Discourse partitioner. Split data on several fuzzy sets
|
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
|
Universe of Discourse partitioner scheme. Split data on several fuzzy sets
|
||||||
:param name: partitioner name
|
:param name: partitioner name
|
||||||
@ -28,31 +29,33 @@ class Partitioner(object):
|
|||||||
self.transformation = transformation
|
self.transformation = transformation
|
||||||
self.indexer = indexer
|
self.indexer = indexer
|
||||||
|
|
||||||
if self.indexer is not None:
|
if preprocess:
|
||||||
ndata = self.indexer.get_data(data)
|
|
||||||
else:
|
|
||||||
ndata = data
|
|
||||||
|
|
||||||
if transformation is not None:
|
if self.indexer is not None:
|
||||||
ndata = transformation.apply(ndata)
|
ndata = self.indexer.get_data(data)
|
||||||
else:
|
else:
|
||||||
ndata = data
|
ndata = data
|
||||||
|
|
||||||
_min = min(ndata)
|
if transformation is not None:
|
||||||
if _min < 0:
|
ndata = transformation.apply(ndata)
|
||||||
self.min = _min * 1.1
|
else:
|
||||||
else:
|
ndata = data
|
||||||
self.min = _min * 0.9
|
|
||||||
|
|
||||||
_max = max(ndata)
|
_min = min(ndata)
|
||||||
if _max > 0:
|
if _min < 0:
|
||||||
self.max = _max * 1.1
|
self.min = _min * 1.1
|
||||||
else:
|
else:
|
||||||
self.max = _max * 0.9
|
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):
|
def build(self, data):
|
||||||
"""
|
"""
|
||||||
@ -74,16 +77,25 @@ class Partitioner(object):
|
|||||||
ticks = []
|
ticks = []
|
||||||
x = []
|
x = []
|
||||||
for s in self.sets:
|
for s in self.sets:
|
||||||
if s.mf == Membership.trimf:
|
if s.type == 'common':
|
||||||
ax.plot([s.parameters[0], s.parameters[1], s.parameters[2]], [0, 1, 0])
|
self.plot_set(ax, s)
|
||||||
elif s.mf == Membership.gaussmf:
|
elif s.type == 'composite':
|
||||||
tmpx = [kk for kk in np.arange(s.lower, s.upper)]
|
for ss in s.sets:
|
||||||
tmpy = [s.membership(kk) for kk in np.arange(s.lower, s.upper)]
|
self.plot_set(ax, ss)
|
||||||
ax.plot(tmpx, tmpy)
|
|
||||||
ticks.append(str(round(s.centroid,0))+'\n'+s.name)
|
ticks.append(str(round(s.centroid,0))+'\n'+s.name)
|
||||||
x.append(s.centroid)
|
x.append(s.centroid)
|
||||||
plt.xticks(x,ticks)
|
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):
|
def __str__(self):
|
||||||
tmp = self.name + ":\n"
|
tmp = self.name + ":\n"
|
||||||
|
19
pyFTS/tests/seasonal.py
Normal file
19
pyFTS/tests/seasonal.py
Normal 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()
|
Loading…
Reference in New Issue
Block a user