ts-aggregator/project_template/DMTrendAddSeasonality.cpp
2022-12-13 12:36:06 +04:00

156 lines
4.2 KiB
C++

//
// Ìåòîä ýêñïîíåíöèàëüíîãî ñãëàæèâàíèÿ è ïðîãíîçèðîâàíèÿ:
// äåìïèíã ìóëüòèïëèêàòèâíûé òðåíä, àääèòèâíàÿ ñåçîííîñòü
//
#include "StdAfx.h"
#include "math.h"
#include <iostream>
#include "DMTrendAddSeasonality.h"
#include "Param.h"
// êîíñòðóêòîð ñ çàäàííûìè íåïîñðåäñòâåííî ïàðàìåòðàìè
DMTrendAddSeasonality::DMTrendAddSeasonality(vector<double> timeSeries, int countPointForecast) {
this->x = timeSeries;
this->countPointForecast = countPointForecast;
this->partition();
}
DMTrendAddSeasonality::~DMTrendAddSeasonality() {
// îñâîáîæäàåòñÿ ïàìÿòü
std::vector<double> ().swap(S);
std::vector<double> ().swap(x);
std::vector<double> ().swap(T);
std::vector<double> ().swap(I);
std::vector<double> ().swap(forecast);
}
// èíèöèàëèçàöèÿ ìîäåëè, çàäàíèå ïåðâîíà÷àëüíûõ çíà÷åíèé
void DMTrendAddSeasonality::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 DMTrendAddSeasonality::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 DMTrendAddSeasonality::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); // óðîâåíü
T.push_back(pow(T[t], phi) + alpha * gamma * e / S[t]); // òðåíä
I.push_back(I[t] + delta * e); // ñåçîííîñòü
forecast.push_back(S[t+1] * pow(T[t+1], phi) + I[t+1]); // ïðîãíîç
}
}
// ñôîðìèðîâàòü ìîäåëü
void DMTrendAddSeasonality::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); // óðîâåíü
T.push_back(pow(T[t], phi) + alpha * gamma * e / S[t]); // òðåíä
I.push_back(I[t] + delta * e); // ñåçîííîñòü
forecast.push_back(S[t+1] * pow(T[t+1], phi) + I[t+1]); // ïðîãíîç
}
}
// ìåòîä ïîëó÷åíèÿ ïðîãíîçà
vector<double> DMTrendAddSeasonality::getForecast() {
vector<double> result;
for (unsigned int i = forecast.size() - countPointForecast; i < forecast.size(); i++) {
result.push_back(forecast[i]);
}
return result;
}
// ìåòîä ïîëó÷åíèÿ îöåíêè ìîäåëè
double DMTrendAddSeasonality::calcEstimation(Aic *aic) {
return aic->getValue(3, this->xEstimation, this->forecast);
}
// ìåòîä ïîëó÷åíèÿ îïòèìèçèðîâàííîãî çíà÷åíèÿ îäíîãî ïàðàìåòðà
// TODO: ðåàëèçîâàòü
Param* DMTrendAddSeasonality::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("ph", 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;
}