pyFTS/partitioners/FCM.py
Petrônio Cândido de Lima e Silva 962ef89bcf - Optimizations and bugfixes on Multi Seasonal Ensemble
- Bugfixes on ProbabilityDistribution
 - Indexers on Partitioners
2017-07-04 16:30:53 -03:00

131 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import numpy as np
import math
import random as rnd
import functools,operator
from pyFTS.common import FuzzySet,Membership
from pyFTS.partitioners import partitioner
#import CMeans
# S. T. Li, Y. C. Cheng, and S. Y. Lin, “A FCM-based deterministic forecasting model for fuzzy time series,”
# Comput. Math. Appl., vol. 56, no. 12, pp. 30523063, Dec. 2008. DOI: 10.1016/j.camwa.2008.07.033.
def fuzzy_distance(x, y):
if isinstance(x, list):
tmp = functools.reduce(operator.add, [(x[k] - y[k])**2 for k in range(0,len(x))])
else:
tmp = (x - y) ** 2
return math.sqrt(tmp)
def membership(val, vals):
soma = 0
for k in vals:
if k == 0:
k = 1
soma = soma + (val / k) ** 2
return soma
def fuzzy_cmeans(k, dados, tam, m, deltadist=0.001):
tam_dados = len(dados)
# Inicializa as centróides escolhendo elementos aleatórios dos conjuntos
centroides = [dados[rnd.randint(0, tam_dados-1)] for kk in range(0, k)]
# Tabela de pertinência das instâncias aos grupos
grupos = [[0 for kk in range(0, k)] for xx in range(0, tam_dados)]
alteracaomedia = 1000
m_exp = 1 / (m - 1)
# para cada instância
iteracoes = 0
while iteracoes < 1000 and alteracaomedia > deltadist:
alteracaomedia = 0
# verifica a distância para cada centroide
# Atualiza a pertinencia daquela instância para cada um dos grupos
inst_count = 0
for instancia in dados:
dist_grupos = [0 for xx in range(0, k)]
grupo_count = 0
for grupo in centroides:
dist_grupos[grupo_count] = fuzzy_distance(grupo, instancia)
grupo_count = grupo_count + 1
dist_grupos_total = functools.reduce(operator.add, [xk for xk in dist_grupos])
for grp in range(0, k):
if dist_grupos[grp] == 0:
grupos[inst_count][grp] = 1
else:
grupos[inst_count][grp] = 1 / membership(dist_grupos[grp], dist_grupos)
# grupos[inst_count][grp] = 1/(dist_grupos[grp] / dist_grupos_total)
# grupos[inst_count][grp] = (1/(dist_grupos[grp]**2))**m_exp / (1/(dist_grupos_total**2))**m_exp
inst_count = inst_count + 1
# return centroides
# atualiza cada centroide com base na Média de todos os padrões ponderados pelo grau de pertinência
grupo_count = 0
for grupo in centroides:
if tam > 1:
oldgrp = [xx for xx in grupo]
for atr in range(0, tam):
soma = functools.reduce(operator.add,
[grupos[xk][grupo_count] * dados[xk][atr] for xk in range(0, tam_dados)])
norm = functools.reduce(operator.add, [grupos[xk][grupo_count] for xk in range(0, tam_dados)])
centroides[grupo_count][atr] = soma / norm
else:
oldgrp = grupo
soma = functools.reduce(operator.add,
[grupos[xk][grupo_count] * dados[xk] for xk in range(0, tam_dados)])
norm = functools.reduce(operator.add, [grupos[xk][grupo_count] for xk in range(0, tam_dados)])
centroides[grupo_count] = soma / norm
alteracaomedia = alteracaomedia + fuzzy_distance(oldgrp, grupo)
grupo_count = grupo_count + 1
alteracaomedia = alteracaomedia / k
iteracoes = iteracoes + 1
return centroides
class FCMPartitioner(partitioner.Partitioner):
"""
"""
def __init__(self, data,npart,func = Membership.trimf, transformation=None, indexer=None):
super(FCMPartitioner, self).__init__("FCM", data, npart, func=func, transformation=transformation, indexer=indexer)
def build(self,data):
sets = []
centroids = fuzzy_cmeans(self.partitions, data, 1, 2)
centroids.append(self.max)
centroids.append(self.min)
centroids = list(set(centroids))
centroids.sort()
for c in np.arange(1,len(centroids)-1):
if self.membership_function == Membership.trimf:
sets.append(FuzzySet.FuzzySet(self.prefix+str(c),Membership.trimf,
[round(centroids[c-1],3), round(centroids[c],3), round(centroids[c+1],3)],
round(centroids[c],3) ) )
elif self.membership_function == Membership.trapmf:
q1 = (round(centroids[c], 3) - round(centroids[c - 1], 3))/2
q2 = (round(centroids[c+1], 3) - round(centroids[c], 3)) / 2
sets.append(FuzzySet.FuzzySet(self.prefix + str(c), Membership.trimf,
[round(centroids[c - 1], 3), round(centroids[c], 3) - q1,
round(centroids[c], 3) + q2, round(centroids[c + 1], 3)],
round(centroids[c], 3)))
return sets