417 lines
14 KiB
C++
417 lines
14 KiB
C++
#include "stdafx.h"
|
|
#include <iostream>
|
|
#include "Method.h"
|
|
#include "Dsa.h"
|
|
#include "Aic.h"
|
|
#include "AicWeights.h"
|
|
#include "Normalization.h"
|
|
#include "Mape.h"
|
|
#include "SMape.h"
|
|
#include "Vovk.h"
|
|
#include "NoTrendNoSeasonality.h"
|
|
#include "NoTrendAddSeasonality.h"
|
|
#include "NoTrendMultSeasonality.h"
|
|
#include "AddTrendNoSeasonality.h"
|
|
#include "AddTrendAddSeasonality.h"
|
|
#include "AddTrendMultSeasonality.h"
|
|
#include "MultTrendNoSeasonality.h"
|
|
#include "MultTrendAddSeasonality.h"
|
|
#include "MultTrendMultSeasonality.h"
|
|
#include "DATrendNoSeasonality.h"
|
|
#include "DATrendAddSeasonality.h"
|
|
#include "DATrendMultSeasonality.h"
|
|
#include "DMTrendNoSeasonality.h"
|
|
#include "DMTrendAddSeasonality.h"
|
|
#include "DMTrendMultSeasonality.h"
|
|
#include "Tsaur.h"
|
|
#include "A.h"
|
|
#include "Fuzzy.h"
|
|
#include "FuzzyWithSets.h"
|
|
#include "File.h"
|
|
#include <vector>
|
|
#include "Param.h"
|
|
#include <sstream>
|
|
#include <direct.h>
|
|
#include <string>
|
|
#include <limits>
|
|
#include <math.h>
|
|
#include "Transformation.h"
|
|
#include "nlopt.hpp"
|
|
#include "nlopt.h"
|
|
#include "BIC.h"
|
|
|
|
|
|
int iMethod; // íîìåð òåêóùåãî ìåòîäà
|
|
const int n = 29; // êîëè÷åñòâî ìåòîäîâ, ÷òîá ëèøíåãî ïàìÿòè íå æðàòü
|
|
int numberParam; // ÷èñëî ïàðàìåòðîâ ó ìåòîäà
|
|
Method** m = new Method*[n];
|
|
Estimation* est1 = new SMape();
|
|
int ii; // ñ÷åò÷èê èòåðàöèé
|
|
|
|
double round (double value) {
|
|
return floor(value + 0.5);
|
|
}
|
|
|
|
double myRound(double num) {
|
|
double n = ((double)round(num * 1000)) / 1000;
|
|
return n;
|
|
}
|
|
|
|
|
|
void printTs(vector<double> ts) {
|
|
for (unsigned int i = 0; i < ts.size(); i++) {
|
|
cout << ts[i];
|
|
cout << " ";
|
|
}
|
|
}
|
|
|
|
double getEstimation(const std::vector<double> &x, std::vector<double> &grad, void *f_data)
|
|
{
|
|
ii++; // ñ÷åò÷èê èòåðàöèé
|
|
|
|
int radix = 10; //ñèñòåìà ñ÷èñëåíèÿ
|
|
char sbuffer[10]; //ðåçóëüòàò
|
|
|
|
for (int iiParam = 0; iiParam < numberParam; iiParam++)
|
|
{
|
|
|
|
m[iMethod]->setParam(itoa(iiParam, sbuffer, radix), myRound(x[iiParam]));
|
|
}
|
|
|
|
m[iMethod]->createModelForEstimation();
|
|
|
|
double smapeValue = myRound(est1->getValue(m[iMethod]->x, m[iMethod]->getForecast()));
|
|
return smapeValue;
|
|
}
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
|
|
Param* bestParams = new Param();
|
|
double bestSmape = DBL_MAX;
|
|
double bestAic = DBL_MAX;
|
|
int bestMethodIndex = 0;
|
|
|
|
setlocale(LC_ALL, "Russian");
|
|
string path;
|
|
string fileName;
|
|
string s;
|
|
if (argc < 1) {
|
|
cout << "set ts file like 'project_template.exe 1.csv count_forecast period!!!";
|
|
return 0;
|
|
} else {
|
|
stringstream ss;
|
|
ss << argv[1];
|
|
ss >> s;
|
|
int found = 0;
|
|
int offset =0;
|
|
do {
|
|
found = s.find("\\", found +1);
|
|
if (found > 0) {
|
|
offset = found;
|
|
cout << found << "\n";
|
|
}
|
|
} while (found!=std::string::npos);
|
|
if (offset ==0) {
|
|
fileName = s.substr(offset, s.length());
|
|
} else {
|
|
fileName = s.substr(offset+1, s.length());
|
|
}
|
|
path = s.substr(0, offset);
|
|
}
|
|
// îáúåêò äëÿ ðàáîòû ñ ôàéëàìè: çàãðóçèòü è ñîõðàíèòü ÂÐ
|
|
vector<double> timeSeries = File::readFile(argv[1]);
|
|
Transformation *transform = new Transformation(timeSeries);
|
|
transform->seasonalPeriod = atof(argv[3]);
|
|
// timeSeries = transform->Normalization();
|
|
//transform->setTimeSeries(tsTransform);
|
|
transform->lambdaEstimation();
|
|
timeSeries = transform->ModifiedBoxCox();
|
|
|
|
Normalization * norm = new Normalization();
|
|
//timeSeries = norm->normalizeTimeSeria(timeSeries);
|
|
|
|
// ñêîëüêî òî÷åê áóäåì ïðîãíîçèðîâàòü
|
|
int pointForecast = 18;
|
|
if (strcmp(argv[2], "") != 0) {
|
|
pointForecast = atof(argv[2]);
|
|
}
|
|
int p = 12;
|
|
if (strcmp(argv[3], "") != 0) {
|
|
p = atof(argv[3]);
|
|
}
|
|
double alpha = 0.1;
|
|
double delta = 0.2;
|
|
double gamma = 0.4;
|
|
double phi = 0.1;
|
|
int countRulesIn = 1;
|
|
int countFuzzyParts = 2;
|
|
// äàëåå çàäàåì ïàðàìåòðû, ñïåöèôè÷íûå äëÿ ìåòîäîâ
|
|
//...
|
|
// òàê êàê èñïîëüçîâàòü áóäåì âñå ìåòîäû (èëè îáúåäèíÿòü â êîëëåêòèâû) íóæíî
|
|
// âñå èõ ïðîèíèöèàëèçèðîâàòü è çàãíàòü â ìàññèâ
|
|
|
|
m[0] = new NoTrendNoSeasonality(timeSeries, pointForecast);
|
|
m[1] = new NoTrendAddSeasonality(timeSeries, pointForecast);
|
|
m[2] = new NoTrendMultSeasonality(timeSeries, pointForecast);
|
|
|
|
m[3] = new AddTrendNoSeasonality(timeSeries, pointForecast);
|
|
m[4] = new MultTrendNoSeasonality(timeSeries, pointForecast);
|
|
m[5] = new DATrendNoSeasonality(timeSeries, pointForecast);
|
|
m[6] = new DMTrendNoSeasonality(timeSeries, pointForecast);
|
|
|
|
m[7] = new AddTrendAddSeasonality(timeSeries, pointForecast);
|
|
m[8] = new MultTrendAddSeasonality(timeSeries, pointForecast);
|
|
m[9] = new DATrendAddSeasonality(timeSeries, pointForecast);
|
|
m[10] = new DMTrendAddSeasonality(timeSeries, pointForecast);
|
|
|
|
m[11] = new AddTrendMultSeasonality(timeSeries, pointForecast);
|
|
m[12] = new MultTrendMultSeasonality(timeSeries, pointForecast);
|
|
m[13] = new DATrendMultSeasonality(timeSeries, pointForecast);
|
|
m[14] = new DMTrendMultSeasonality(timeSeries, pointForecast);
|
|
m[15] = new Dsa(timeSeries, pointForecast);
|
|
m[16] = new Fuzzy("None", "None", timeSeries, pointForecast);
|
|
m[17] = new Fuzzy("Add", "None", timeSeries, pointForecast);
|
|
m[18] = new Fuzzy("None", "Add", timeSeries, pointForecast);
|
|
m[19] = new Fuzzy("Add", "Add", timeSeries, pointForecast);
|
|
m[20] = new FuzzyWithSets("None", "None", timeSeries, pointForecast);
|
|
m[21] = new FuzzyWithSets("None", "Add", timeSeries, pointForecast);
|
|
m[22] = new FuzzyWithSets("None", "Mult", timeSeries, pointForecast);
|
|
m[23] = new FuzzyWithSets("Add", "None", timeSeries, pointForecast);
|
|
m[24] = new FuzzyWithSets("Add", "Add", timeSeries, pointForecast);
|
|
m[25] = new FuzzyWithSets("Add", "Mult", timeSeries, pointForecast);
|
|
m[26] = new FuzzyWithSets("Mult", "None", timeSeries, pointForecast);
|
|
m[27] = new FuzzyWithSets("Mult", "Add", timeSeries, pointForecast);
|
|
m[28] = new FuzzyWithSets("Mult", "Mult", timeSeries, pointForecast);
|
|
//m[29] = new Tsaur(timeSeries, pointForecast);
|
|
|
|
AicWeights *aicWeights = new AicWeights();
|
|
vector<double> aicValues;
|
|
vector<vector<double>> modelsResults;
|
|
vector<Param*> optimal;
|
|
string smapeResults = "";
|
|
|
|
for (int i = 15; i < n; i++) {
|
|
iMethod = i;
|
|
m[i]->setParam("p", p);
|
|
// âûçîâåì ìåòîä îïòèìèçàöèè îäíîãî ïàðàìåòðà
|
|
//Estimation *est1 = new SMape();
|
|
Estimation *est1 = new Bic(algoritm::RMSE, m[i]->getNamberParam());
|
|
//optimal.push_back(m[i]->optimize(est1));
|
|
|
|
numberParam = m[i]->getNamberParam();
|
|
|
|
if (numberParam == 1) // äëÿ îäíîãî ïàðàìåòðà ïðîùå ïåðåáîð ïî ñåòêå
|
|
{
|
|
optimal.push_back(m[i]->optimize(est1));
|
|
m[i]->setParam("alpha", optimal[optimal.size()-1]->alpha);
|
|
}
|
|
else
|
|
{
|
|
// âåêòîðà äëÿ íà÷àëüíûõ, ìèíèìàëüíûõ è ìàêñèìàëüíûõ çíà÷åíèé ïàðàìåòðîâ
|
|
std::vector<double> x(numberParam);
|
|
std::vector<double> lb(numberParam);
|
|
std::vector<double> ub(numberParam);
|
|
|
|
// óñòàíàâëèâàåì ïàðàìåòðû
|
|
for (int iParam = 0; iParam < numberParam; iParam++)
|
|
{
|
|
lb[iParam] = 0.01; // ìèíèìàëüíîå çíà÷åíèå ïàðàìåòðà
|
|
ub[iParam] = 0.99; // ìàêñèìàëüíîå çíà÷åíèå ïåðåìåòðà
|
|
x[iParam] = 0.3; // íà÷àëüíîå çíà÷åíèå ïàðàìåòðà
|
|
}
|
|
|
|
// ñîçäàåì îñíîâíîé ìåòîä îïòèìèçàöèè
|
|
nlopt::opt opt(nlopt::AUGLAG, numberParam);
|
|
|
|
// ñîçäàåì âñïîìàãàòåëüíûé ìåòîä îïòèìèçàöèè
|
|
nlopt::opt subOpt(nlopt::GN_ORIG_DIRECT_L, numberParam);
|
|
subOpt.set_lower_bounds(lb);
|
|
subOpt.set_upper_bounds(ub);
|
|
|
|
// óñòàíàâëèâàåì ïàðàìåòðû îñíîâíîãî ìåòîäà îïòèìèçàöèè
|
|
opt.set_lower_bounds(lb);
|
|
opt.set_upper_bounds(ub);
|
|
opt.set_local_optimizer(subOpt);
|
|
|
|
// â çàâèñèìîñòè îò ÷èñëà ïàðàìåòðîâ, óñòàíàâëèâàåì êîëè÷åñòâî èòåðàöèé îïòèìèçàöèè
|
|
if (numberParam == 2)
|
|
{
|
|
subOpt.set_maxeval(10000);
|
|
opt.set_maxeval(10000);
|
|
}
|
|
else if (numberParam == 3)
|
|
{
|
|
subOpt.set_maxeval(50000);
|
|
opt.set_maxeval(50000);
|
|
}
|
|
else
|
|
{
|
|
subOpt.set_maxeval(100000);
|
|
opt.set_maxeval(100000);
|
|
}
|
|
|
|
// çàïóñêàåì îïòèìèçàöèþ
|
|
// getEstimation - ìåòîä â ñàìîì ââåðõó, êîòðûé âîçâðàùàåò îøèáêó íà êàæäîé èòåðàöèè
|
|
double minf;
|
|
opt.set_min_objective(getEstimation, NULL);
|
|
nlopt::result subResult = opt.optimize(x, minf);
|
|
|
|
cout << minf << endl;
|
|
|
|
// ïîïûòàåìñÿ óëó÷øèòü ïàðàìåòðû
|
|
nlopt::opt ssubOpt(nlopt::LN_NELDERMEAD, numberParam);
|
|
ssubOpt.set_lower_bounds(lb);
|
|
ssubOpt.set_upper_bounds(ub);
|
|
ssubOpt.set_maxeval(500);
|
|
|
|
ssubOpt.set_min_objective(getEstimation, NULL);
|
|
nlopt::result Result = ssubOpt.optimize(x, minf);
|
|
|
|
cout << minf << endl;
|
|
if (m[i]->getNamberParam() > 1) {
|
|
optimal.push_back(new Param());
|
|
}
|
|
optimal[optimal.size()-1]->countFuzzyParts = x[0] * 100;
|
|
optimal[optimal.size()-1]->countRulesIn = x[1] * 5;
|
|
if (i == 15) {
|
|
optimal[optimal.size()-1]->sizeLabels = x[2] * 100;
|
|
} else {
|
|
optimal[optimal.size()-1]->gamma = x[2];
|
|
}
|
|
if (m[i]->getNamberParam() > 3) {
|
|
optimal[optimal.size()-1]->delta = x[3];
|
|
if (m[i]->getNamberParam() > 4) {
|
|
optimal[optimal.size()-1]->alpha = x[4];
|
|
}
|
|
}
|
|
|
|
// â âåêòîðå x íàéäåííûå ïàðàìåòðû, â min - smape
|
|
|
|
}
|
|
|
|
// ñîçäàåì ìîäåëü äëÿ òåñòèðîâàíèÿ ïðè ïîìîùè âûáðàííîãî ìåòîäà
|
|
// çàäàåì ïàðàìåòðû
|
|
m[i]->setParam("alpha", optimal[optimal.size()-1]->alpha);
|
|
m[i]->setParam("gamma", optimal[optimal.size()-1]->gamma);
|
|
m[i]->setParam("delta", optimal[optimal.size()-1]->delta);
|
|
m[i]->setParam("phi", optimal[optimal.size()-1]->phi);
|
|
m[i]->setParam("countRulesIn", optimal[optimal.size()-1]->countRulesIn);
|
|
m[i]->setParam("countFuzzyParts", optimal[optimal.size()-1]->countFuzzyParts);
|
|
m[i]->setParam("lb1", optimal[optimal.size()-1]->lb1);
|
|
m[i]->setParam("rb1", optimal[optimal.size()-1]->rb1);
|
|
m[i]->setParam("lb2", optimal[optimal.size()-1]->lb2);
|
|
m[i]->setParam("rb2", optimal[optimal.size()-1]->rb2);
|
|
m[i]->setParam("sizeLabels", optimal[optimal.size()-1]->sizeLabels);
|
|
// ñîçäàåì ìîäåëü
|
|
m[i]->createModelForEstimation();
|
|
// âû÷èñëÿåì îøèáêó
|
|
//aicValues.push_back(aic->getValue(4, m[i]->getXEstimation(), m[i]->getForecast()));
|
|
//aicValues.push_back(aic->getAiccValue(4, m[i]->getXEstimation(), m[i]->getForecast()));
|
|
//aicValues.push_back(aic->getBicValue(4, m[i]->getXEstimation(), m[i]->getForecast()));
|
|
//modelsResults.push_back(m[i]->getForecast());
|
|
SMape* smape = new SMape();
|
|
stringstream ss1;
|
|
ss1 << i;
|
|
string str1 = ss1.str();
|
|
stringstream ss2;
|
|
double sm = smape->getValue(m[i]->x, m[i]->getForecast());
|
|
double ai = optimal[optimal.size()-1]->estim;
|
|
ss2 << sm;
|
|
|
|
// îïðåäåëÿåì, ÿâëÿþòñÿ ëè äàííûå ïàðàìåòðû ëó÷øèìè
|
|
if (ai < bestAic) {
|
|
bestAic = ai;
|
|
bestParams = optimal[optimal.size()-1];
|
|
bestMethodIndex = i;
|
|
}
|
|
|
|
string str2 = ss2.str();
|
|
smapeResults = smapeResults + "Smape for " + str1 + " method: " + str2 + " ";
|
|
smapeResults = smapeResults + optimal[optimal.size()-1]->toString() + "\n";
|
|
// ñîçäàåì ìîäåëü ïðè ïîìîùè âûáðàííîãî ìåòîäà
|
|
// ïîëó÷èì è ñîõðàíèì ïðîãíîç
|
|
string target = path +"\\"+ fileName+"result";
|
|
_mkdir(target.c_str());
|
|
string fileNameOut = target + "\\";
|
|
char suff[3];
|
|
itoa(i, suff, 10);
|
|
fileNameOut.append(suff);
|
|
fileNameOut.append("out");
|
|
m[i]->createModel();
|
|
//File::writeFile(fileNameOut, norm->deNormalizeTimeSeria(m[i]->getForecast()));
|
|
//transform->setTimeSeries(m[i]->getForecast());
|
|
//transform->setTimeSeries(transform->invModifiedBoxCox());
|
|
transform->setTimeSeries(m[i]->getForecast());
|
|
File::writeFile(fileNameOut, transform->invModifiedBoxCox());
|
|
|
|
}
|
|
Method* bestMethod = m[bestMethodIndex];
|
|
// ïîñëå òîãî, êàê îòðàáîòàëè âñå ìîäåëè
|
|
// çàäàåì ëó÷øèå ïàðàìåòðû
|
|
bestMethod->setParam("alpha", bestParams->alpha);
|
|
bestMethod->setParam("gamma", bestParams->gamma);
|
|
bestMethod->setParam("delta", bestParams->delta);
|
|
|
|
bestMethod->setParam("phi", bestParams->phi);
|
|
|
|
bestMethod->setParam("countRulesIn", bestParams->countRulesIn);
|
|
bestMethod->setParam("countFuzzyParts", bestParams->countFuzzyParts);
|
|
bestMethod->setParam("lb1", bestParams->lb1);
|
|
bestMethod->setParam("rb1", bestParams->rb1);
|
|
bestMethod->setParam("lb2", bestParams->lb2);
|
|
bestMethod->setParam("rb2", bestParams->rb2);
|
|
bestMethod->setParam("sizeLabels", bestParams->sizeLabels);
|
|
bestMethod->createModel();
|
|
string target = path +"\\"+ fileName+"result";
|
|
string fileNameOut = target + "\\";
|
|
fileNameOut.append("best");
|
|
char _s[3];
|
|
itoa(bestMethodIndex, _s, 10);
|
|
fileNameOut.append(_s);
|
|
//File::writeFile(fileNameOut, norm->deNormalizeTimeSeria(bestMethod->getForecast()));
|
|
transform->setTimeSeries(bestMethod->getForecast());
|
|
File::writeFile(fileNameOut, transform->invModifiedBoxCox());
|
|
|
|
|
|
string smapeFileName = path +"\\"+ fileName+"result\\smape";
|
|
FILE * file = fopen(smapeFileName.c_str(), "w");
|
|
if (file) // åñëè åñòü äîñòóï ê ôàéëó,
|
|
{
|
|
bool result = fputs(smapeResults.c_str(), file); // è çàïèñûâàåì åå â ôàéë
|
|
if (!result) // åñëè çàïèñü ïðîèçîøëà óñïåøíî
|
|
cout << "Ñòðîêà â ôàéë óñïåøíî çàïèñàíà!"; // âûâîäèì ñîîáùåíèå
|
|
fclose(file);
|
|
}
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Vovk *vovk = new Vovk(timeSeries, pointForecast, m);
|
|
vector<double> res;
|
|
res.push_back(vovk->getForecast());
|
|
for (int i = 0; i < pointForecast - 1; i++){
|
|
//cout << i + 1 << " " << vovk->getForecast() << endl;
|
|
vovk->updateTS(res[res.size() - 1]);
|
|
res.push_back(vovk->getForecast());
|
|
}
|
|
res = norm->deNormalizeTimeSeria(res);
|
|
for (int i = 0; i < pointForecast - 1; i++){
|
|
cout << i + 1 << " " << res[i] << endl;
|
|
}
|
|
SMape *smape = new SMape();
|
|
cout << "Smape for Vovk " << " method: " << smape->getValue(norm->deNormalizeTimeSeria(m[0]->getXEstimation()), res) << "\n";
|
|
vector<double> weights = aicWeights->calculateWeights(aicValues);
|
|
vector<double> fuzzyAdoptiveWeights = aicWeights->calculateFuzzyAdaptiveWeights(timeSeries, modelsResults);
|
|
cout << "Smape for etalon forecast " << " method: " << smape->getValue(m[21]->getXEstimation(), m[21]->getXEstimation()) << "\n";
|
|
|
|
delete(m);
|
|
return 0;
|
|
}
|
|
|
|
|