#include "StdAfx.h" #include "Dsa.h" #include #include "Param.h" Dsa::Dsa(vector timeSeries, int countPointForecast){ this->countPointForecast = countPointForecast; this->x = timeSeries; this->partition(); } Dsa::~Dsa(void) { } void Dsa::init() { defineUniversum(); fuzzyTs.clear(); } // определить универсум для временного ряда // ищем максимум, минимум, производим разбиение на заданные интервалы void Dsa::defineUniversum() { this->universumMax = x[0]; this->universumMin = x[0]; for (int i = 1; i < x.size(); i++) { if (universumMax < x[i]) { universumMax = x[i]; } if (universumMin > x[i]) { universumMin = x[i]; } } // создаем функции принадлежности // принимаем по умолчанию, что соседние перекрываются на половину между собой // раз есть количество интервалов, то вычисляем размер основания треугольника double baseSize = (universumMax - universumMin) / countFuzzyParts; a.resize(countFuzzyParts + 1); for (int i=0; i < countFuzzyParts + 1;i++){ a[i] = (A(universumMin + (i-sizeLabels) * baseSize, universumMin + (i+sizeLabels)*baseSize)); } } // фаззифицировать только одну точку // возвращает индекс функции принадлежности с максимальным значением int Dsa::fuzzyfication(double value) { // перебираем все функции принадлежности, // если нашли наибольшую степень принадлежности, то фиксируем индекс функции int indMax = 0; double max = a[0].getValue(value); for (int j =0; j < a.size(); j++) { if (a[j].getValue(value) > max) { indMax = j; max = a[j].getValue(value); } } return indMax; } void Dsa::createRules() { rulesIn.clear(); rulesIn.resize(fuzzyTs.size() - countRulesIn); rulesOut.clear(); rulesOut.resize(fuzzyTs.size() - countRulesIn); for (int i=0; i < fuzzyTs.size() - countRulesIn; i ++) { vector v; v.resize(countRulesIn); for (int j=i; j < i + countRulesIn; j++) { v[j-i] = fuzzyTs[j]; } rulesIn[i] = v; rulesOut[i] = fuzzyTs[i+countRulesIn]; } } vector Dsa::searchRules(vector inPart) { vector res; for (int i = 0; i < rulesIn.size(); i++) { bool isRuleFound = true; for (int j = 0; j < rulesIn[i].size(); j++) { if (rulesIn[i][j] != inPart[j]) { isRuleFound = false; } } if (isRuleFound) { res.push_back(rulesOut[i]); } } return res; } vector Dsa::searchRulesForSeason(int index) { vector res; int i =index - p; while (i > 0) { res.push_back(fuzzyfication(x[i])); i -= p; } return res; } void Dsa::createModelForEstimation() { init(); fuzzyTs.resize(xLearning.size()); for (int t = 0; t < xLearning.size(); t++) { fuzzyTs[t] = fuzzyfication(xLearning[t]); } createRules(); forecast.clear(); forecast.resize(fuzzyTs.size()+countPointForecast); for (int i=0; i < fuzzyTs.size();i++) { forecast[i] = defuzzyfication(fuzzyTs[i]); } int k = fuzzyTs.size(); for (int i=0; i < countPointForecast;i++) { vector lastPoints; lastPoints.resize(countRulesIn); for (int j = countRulesIn; j > 0; j--) { lastPoints[countRulesIn -j] = (fuzzyTs[fuzzyTs.size() - j]); } double sum = 0; // сезонная компонента vector foundSeasonFuncs = searchRulesForSeason(fuzzyTs.size()); for (int j =0; j < foundSeasonFuncs.size(); j++) { sum += a[foundSeasonFuncs[j]].getValueAtTop(); } double valueAtSeason = sum / foundSeasonFuncs.size(); forecast[i+k] = (valueAtSeason); int index = fuzzyfication(forecast[i+k]); // добавить прогнозую точку в конец ряда fuzzyTs.push_back(index); xLearning.push_back(forecast[i+k]); createRules(); } for (int i=0; i < countPointForecast;i++) { if (fuzzyTs.size() > 0) fuzzyTs.pop_back(); if (rulesIn.size() > 0) rulesIn.pop_back(); if (rulesOut.size() > 0) rulesOut.pop_back(); xLearning.pop_back(); } } // фаззиикация, создать список функций принадлежности по всему ряду void Dsa::createModel() { init(); fuzzyTs.resize(x.size()); for (int i = 0; i < x.size(); i++) { fuzzyTs[i] = fuzzyfication(x[i]); } createRules(); forecast.clear(); forecast.resize(fuzzyTs.size()+countPointForecast); for (int i=0; i < fuzzyTs.size();i++) { forecast[i] = defuzzyfication(fuzzyTs[i]); } int k = fuzzyTs.size(); for (int i=0; i < countPointForecast;i++) { vector lastPoints; lastPoints.resize(countRulesIn); for (int j = countRulesIn; j > 0; j--) { lastPoints[countRulesIn -j] = (fuzzyTs[fuzzyTs.size() - j]); } double sum = 0; // сезонная компонента vector foundSeasonFuncs = searchRulesForSeason(fuzzyTs.size()); for (int j =0; j < foundSeasonFuncs.size(); j++) { sum += a[foundSeasonFuncs[j]].getValueAtTop(); } double valueAtSeason = sum / foundSeasonFuncs.size(); forecast[i+k] = (valueAtSeason); int index = fuzzyfication(forecast[i+k]); // добавить прогнозую точку в конец ряда fuzzyTs.push_back(index); x.push_back(forecast[i+k]); createRules(); } for (int i=0; i < countPointForecast;i++) { if (fuzzyTs.size() > 0) fuzzyTs.pop_back(); if (rulesIn.size() > 0) rulesIn.pop_back(); if (rulesOut.size() > 0) rulesOut.pop_back(); x.pop_back(); } } vector Dsa::getForecast() { vector result; for (unsigned int i = forecast.size() - countPointForecast; i < forecast.size(); i++) { result.push_back(forecast[i]); } return forecast; } double Dsa::defuzzyfication(int index) { return this->a[index].getValueAtTop(); } void Dsa::setParam(string paramName, double value) { if (paramName.compare("countFuzzyParts") == 0) { this->countFuzzyParts = value; } else if (paramName.compare("countRulesIn") == 0) { if (this->xLearning.size() < value) { this->countRulesIn = this->xLearning.size(); } else { this->countRulesIn = value; } } else if (paramName.compare("p") == 0) { if (value <= 0) { this->p = 1; } else { this->p = value; } } else if (paramName.compare("sizeLabels") == 0) { this->sizeLabels = value; } if (paramName.compare("0") == 0) { this->countFuzzyParts = value * 100; } else if (paramName.compare("1") == 0) { if (this->xLearning.size() < value * 5) { this->countRulesIn = this->xLearning.size(); } else { this->countRulesIn = value * 5; } } else if (paramName.compare("2") == 0) { this->sizeLabels = value * 100; } } // метод получения оценки модели double Dsa::calcEstimation(Aic *aic) { return aic->getValue(3, this->xEstimation, this->forecast); } // метод получения оптимизированного значения одного параметра // TODO: реализовать Param* Dsa::optimize(Estimation *est) { Param *optimal = new Param(); double minSmape = 99999; for (double cfp = 2; cfp < 50;cfp+= 1) { cout << "DSA " << cfp << " из 50" <<"\n";; for (double cri = 1; cri < 5;cri+=1) { for (double sizeLabels = 1; sizeLabels < 50; sizeLabels+= 1) { this->setParam("countRulesIn", cri); this->setParam("countFuzzyParts", cfp); this->setParam("sizeLabels", sizeLabels); double smapeValue = 0; int maxShift = 5; if (maxShift > this->countPointForecast) { maxShift = this->countPointForecast-1; } this->countPointForecast -= maxShift; for (int shift=0; shift <= maxShift; shift++) { this->partition(); this->createModelForEstimation(); smapeValue += est->getValue(x, getForecast()); this->countPointForecast++; } this->countPointForecast--; smapeValue = smapeValue / maxShift; if (minSmape > smapeValue) { minSmape = smapeValue; optimal->countFuzzyParts = cfp; optimal->countRulesIn = cri; optimal->estim = smapeValue; optimal->sizeLabels = sizeLabels; } } } } return optimal; } int Dsa::getNamberParam() { return 3; }