// // Метод экспоненциального сглаживания и прогнозирования: // демпинг мультипликативный тренд, мультипликатвная сезонность // #include "StdAfx.h" #include "math.h" #include #include "DMTrendMultSeasonality.h" #include "Param.h" // конструктор с заданными непосредственно параметрами DMTrendMultSeasonality::DMTrendMultSeasonality(vector timeSeries, int countPointForecast) { this->x = timeSeries; this->countPointForecast = countPointForecast; this->partition(); } DMTrendMultSeasonality::~DMTrendMultSeasonality() { // освобождается память std::vector ().swap(S); std::vector ().swap(x); std::vector ().swap(T); std::vector ().swap(I); std::vector ().swap(forecast); } // инициализация модели, задание первоначальных значений void DMTrendMultSeasonality::init() { S.clear(); T.clear(); I.clear(); forecast.clear(); double sumS = 0; double sumT = 0; for (unsigned int t = 0; t < p; t++) { sumS += x[t]; sumT += x[t+p]; } S.push_back(sumS / p); T.push_back((sumT/ p - S[0]) / p); for (unsigned int t = 0; t < p; t++) { I.push_back(x[t] / S[0]); } forecast.push_back(S[0] * pow(T[0], phi) * I[0]); } // Задать параметр void DMTrendMultSeasonality::setParam(string paramName, double value) { if (paramName.compare("alpha") == 0) { this->alpha = value; } else if (paramName.compare("gamma") == 0) { this->gamma = value; } else if (paramName.compare("p") == 0) { this->p = value; } else if (paramName.compare("delta") == 0) { this->delta = value; } else if (paramName.compare("phi") == 0) { this->phi = value; } } // сформировать модель void DMTrendMultSeasonality::createModel() { this->init(); // инициализировать модель double e = 0; //выполняется проход модели по сглаживанию и прогнозированию countPointForecast точек for (unsigned int t = 0; t < x.size()-1 + this->countPointForecast; t++) { // пока не дошли до конца ряда - сглаживаем, иначе строим прогноз if (t < x.size()) { e = x[t]-forecast[t]; } else { e = 0; } S.push_back(S[t] * pow(T[t], phi) + alpha * e / I[t]); // уровень T.push_back(pow(T[t], phi) + alpha * gamma * e / (I[t] * S[t])); // тренд I.push_back(I[t] + delta * e / (S[t] * pow(T[t], phi))); // сезонность forecast.push_back(S[t+1] * pow(T[t+1], phi) * I[t+1]); // прогноз } } // сформировать модель с новым значением параметра. перегруженный метод void DMTrendMultSeasonality::createModelForEstimation() { this->init(); // инициализировать модель double e = 0; //выполняется проход модели по сглаживанию и прогнозированию countPointForecast точек for (unsigned int t = 0; t < xLearning.size()-1 + this->countPointForecast; t++) { // пока не дошли до конца ряда - сглаживаем, иначе строим прогноз if (t < xLearning.size()) { e = xLearning[t]-forecast[t]; } else { e = 0; } ` S.push_back(S[t] * pow(T[t], phi) + alpha * e / I[t]); // уровень T.push_back(pow(T[t], phi) + alpha * gamma * e / (I[t] * S[t])); // тренд I.push_back(I[t] + delta * e / (S[t] * pow(T[t], phi))); // сезонность forecast.push_back(S[t+1] * pow(T[t+1], phi) * I[t+1]); // прогноз } } // метод получения прогноза vector DMTrendMultSeasonality::getForecast() { vector result; for (unsigned int i = forecast.size() - countPointForecast; i < forecast.size(); i++) { result.push_back(forecast[i]); } return result; } // метод получения оценки модели double DMTrendMultSeasonality::calcEstimation(Aic *aic) { return aic->getValue(3, this->xEstimation, this->forecast); } // метод получения оптимизированного значения одного параметра // TODO: реализовать Param* DMTrendMultSeasonality::optimize(Estimation *est) { Param *optimal = new Param(); double minSmape = 99999; for (double al = 0.1; al < 1; al+= 0.05) { for (double gam = 0.1; gam < 1; gam+= 0.05) { for (double del = 0.1; del < 1;del+= 0.05) { for (double ph = 0.1; ph < 1;ph+= 0.05) { this->setParam("alpha", al); this->setParam("gamma", gam); this->setParam("delta", del); this->setParam("phi", ph); this->createModelForEstimation(); double smapeValue = est->getValue(getXEstimation(), getForecast()); if (minSmape > smapeValue) { minSmape = smapeValue; optimal->alpha = al; optimal->gamma = gam; optimal->delta = del; optimal->phi = ph; } } } } } return optimal; }