From 9e3ecc1d31d167f175ac10cf31494a0b27f6ae38 Mon Sep 17 00:00:00 2001 From: Anton Romanov Date: Sat, 7 Nov 2020 14:13:56 +0400 Subject: [PATCH] #2 -- fix seasonal model --- build.gradle | 1 + .../ApiConfiguration.java | 2 +- .../ControllersConfiguration.java | 2 +- .../MvcConfiguration.java | 0 .../SecurityConfiguration.java | 2 +- .../SwaggerConfiguration.java | 2 +- .../controllers/TimeSeriesController.java | 2 +- src/main/java/ru/ulstu/pages/IndexView.java | 6 +- .../ru/ulstu/services/TimeSeriesService.java | 12 ++- .../ru/ulstu/tsMethods/TimeSeriesMethod.java | 10 ++- .../exponential/AddTrendAddSeason.java | 85 +++++++++++++++++++ .../exponential/AddTrendNoSeason.java | 11 +-- .../exponential/ExponentialMethodParams.java | 8 ++ .../exponential/ExponentialParamName.java | 2 +- 14 files changed, 120 insertions(+), 25 deletions(-) rename src/main/java/ru/ulstu/{configurations => configuration}/ApiConfiguration.java (72%) rename src/main/java/ru/ulstu/{configurations => configuration}/ControllersConfiguration.java (96%) rename src/main/java/ru/ulstu/{configurations => configuration}/MvcConfiguration.java (100%) rename src/main/java/ru/ulstu/{configurations => configuration}/SecurityConfiguration.java (93%) rename src/main/java/ru/ulstu/{configurations => configuration}/SwaggerConfiguration.java (96%) create mode 100644 src/main/java/ru/ulstu/tsMethods/exponential/AddTrendAddSeason.java diff --git a/build.gradle b/build.gradle index 86dffb0..fc21cec 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'io.spring.dependency-management' version '1.0.9.RELEASE' id 'org.springframework.boot' version '2.3.3.RELEASE' + id "org.sonarqube" version "2.7" } jar { diff --git a/src/main/java/ru/ulstu/configurations/ApiConfiguration.java b/src/main/java/ru/ulstu/configuration/ApiConfiguration.java similarity index 72% rename from src/main/java/ru/ulstu/configurations/ApiConfiguration.java rename to src/main/java/ru/ulstu/configuration/ApiConfiguration.java index 3034402..21622a5 100644 --- a/src/main/java/ru/ulstu/configurations/ApiConfiguration.java +++ b/src/main/java/ru/ulstu/configuration/ApiConfiguration.java @@ -1,4 +1,4 @@ -package ru.ulstu.configurations; +package ru.ulstu.configuration; public class ApiConfiguration { public static final String API_1_0 = "/api/1.0/"; diff --git a/src/main/java/ru/ulstu/configurations/ControllersConfiguration.java b/src/main/java/ru/ulstu/configuration/ControllersConfiguration.java similarity index 96% rename from src/main/java/ru/ulstu/configurations/ControllersConfiguration.java rename to src/main/java/ru/ulstu/configuration/ControllersConfiguration.java index 5d50b57..7cb3e33 100644 --- a/src/main/java/ru/ulstu/configurations/ControllersConfiguration.java +++ b/src/main/java/ru/ulstu/configuration/ControllersConfiguration.java @@ -1,4 +1,4 @@ -package ru.ulstu.configurations; +package ru.ulstu.configuration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/ru/ulstu/configurations/MvcConfiguration.java b/src/main/java/ru/ulstu/configuration/MvcConfiguration.java similarity index 100% rename from src/main/java/ru/ulstu/configurations/MvcConfiguration.java rename to src/main/java/ru/ulstu/configuration/MvcConfiguration.java diff --git a/src/main/java/ru/ulstu/configurations/SecurityConfiguration.java b/src/main/java/ru/ulstu/configuration/SecurityConfiguration.java similarity index 93% rename from src/main/java/ru/ulstu/configurations/SecurityConfiguration.java rename to src/main/java/ru/ulstu/configuration/SecurityConfiguration.java index 1e1a39b..9ad383e 100644 --- a/src/main/java/ru/ulstu/configurations/SecurityConfiguration.java +++ b/src/main/java/ru/ulstu/configuration/SecurityConfiguration.java @@ -1,4 +1,4 @@ -package ru.ulstu.configurations; +package ru.ulstu.configuration; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; diff --git a/src/main/java/ru/ulstu/configurations/SwaggerConfiguration.java b/src/main/java/ru/ulstu/configuration/SwaggerConfiguration.java similarity index 96% rename from src/main/java/ru/ulstu/configurations/SwaggerConfiguration.java rename to src/main/java/ru/ulstu/configuration/SwaggerConfiguration.java index 2458136..02d616a 100644 --- a/src/main/java/ru/ulstu/configurations/SwaggerConfiguration.java +++ b/src/main/java/ru/ulstu/configuration/SwaggerConfiguration.java @@ -1,4 +1,4 @@ -package ru.ulstu.configurations; +package ru.ulstu.configuration; import com.google.common.base.Predicates; import org.springframework.context.annotation.Bean; diff --git a/src/main/java/ru/ulstu/controllers/TimeSeriesController.java b/src/main/java/ru/ulstu/controllers/TimeSeriesController.java index 19b58bc..8d500b3 100644 --- a/src/main/java/ru/ulstu/controllers/TimeSeriesController.java +++ b/src/main/java/ru/ulstu/controllers/TimeSeriesController.java @@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import ru.ulstu.configurations.ApiConfiguration; +import ru.ulstu.configuration.ApiConfiguration; import ru.ulstu.models.ForecastParams; import ru.ulstu.models.TimeSeries; import ru.ulstu.models.exceptions.ModelingException; diff --git a/src/main/java/ru/ulstu/pages/IndexView.java b/src/main/java/ru/ulstu/pages/IndexView.java index 5128a51..0038bbd 100644 --- a/src/main/java/ru/ulstu/pages/IndexView.java +++ b/src/main/java/ru/ulstu/pages/IndexView.java @@ -24,10 +24,10 @@ import java.time.format.DateTimeFormatter; public class IndexView implements Serializable { private final static Logger LOG = LoggerFactory.getLogger(IndexView.class); private LineChartModel model; - private String timeSeriesString = "1,2,3,4"; + private String timeSeriesString = "1,2,3,2,1,2,3,2,1,2,3"; @Autowired - private TimeSeriesService timeSeriesService; + private transient TimeSeriesService timeSeriesService; @PostConstruct public void init() { @@ -57,7 +57,7 @@ public class IndexView implements Serializable { LineChartSeries series3 = new LineChartSeries(); series3.setLabel("Прогноз"); try { - for (TimeSeriesValue value : timeSeriesService.getForecast(timeSeries, 5).getValues()) { + for (TimeSeriesValue value : timeSeriesService.getForecast(timeSeries, 20).getValues()) { series3.set(DateTimeFormatter.ISO_LOCAL_DATE.format(value.getDate()), value.getValue()); } } catch (ModelingException ex) { diff --git a/src/main/java/ru/ulstu/services/TimeSeriesService.java b/src/main/java/ru/ulstu/services/TimeSeriesService.java index f2165e6..109d5f3 100644 --- a/src/main/java/ru/ulstu/services/TimeSeriesService.java +++ b/src/main/java/ru/ulstu/services/TimeSeriesService.java @@ -7,7 +7,7 @@ import ru.ulstu.TimeSeriesUtils; import ru.ulstu.models.TimeSeries; import ru.ulstu.models.TimeSeriesValue; import ru.ulstu.models.exceptions.ModelingException; -import ru.ulstu.tsMethods.exponential.AddTrendNoSeason; +import ru.ulstu.tsMethods.exponential.AddTrendAddSeason; import ru.ulstu.tsMethods.exponential.ExponentialMethodParams; import java.time.LocalDateTime; @@ -17,6 +17,8 @@ import java.util.stream.Collectors; import static ru.ulstu.tsMethods.exponential.ExponentialParamName.ALPHA; import static ru.ulstu.tsMethods.exponential.ExponentialParamName.BETA; +import static ru.ulstu.tsMethods.exponential.ExponentialParamName.GAMMA; +import static ru.ulstu.tsMethods.exponential.ExponentialParamName.SEASON; @Service @@ -35,13 +37,15 @@ public class TimeSeriesService { public TimeSeries getForecast(TimeSeries timeSeries, int countPoints) throws ModelingException { //NoTrendNoSeason nn = new NoTrendNoSeason(ExponentialMethodParams.of(ExponentialParamName.ALPHA, 0.8)); - AddTrendNoSeason an = new AddTrendNoSeason(timeSeries, ExponentialMethodParams.of(ALPHA, 0.8, BETA, 0.8)); + AddTrendAddSeason an = new AddTrendAddSeason(timeSeries, ExponentialMethodParams.of(ALPHA, 0.0, + BETA, 1.0, GAMMA, 1.0, SEASON, 17.0)); return an.getForecast(countPoints); } public TimeSeries smoothTimeSeries(TimeSeries timeSeries) throws ModelingException { //NoTrendNoSeason nn = new NoTrendNoSeason(timeSeries, ExponentialMethodParams.of(ExponentialParamName.ALPHA, 0.8)); - AddTrendNoSeason an = new AddTrendNoSeason(timeSeries, ExponentialMethodParams.of(ALPHA, 0.8, BETA, 0.8)); + AddTrendAddSeason an = new AddTrendAddSeason(timeSeries, ExponentialMethodParams.of(ALPHA, 0.0, + BETA, 1.0, GAMMA, 1.0, SEASON, 17.0)); return an.getModel(); } @@ -68,7 +72,7 @@ public class TimeSeriesService { return timeSeries .getValues() .stream() - .map(v -> v.getValue().toString().replaceAll("\\.", ",")) + .map(v -> v.getValue().toString().replace("\\.", ",")) .collect(Collectors.joining(";")); } } diff --git a/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethod.java b/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethod.java index 969acae..1098c9f 100644 --- a/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethod.java +++ b/src/main/java/ru/ulstu/tsMethods/TimeSeriesMethod.java @@ -49,7 +49,8 @@ public abstract class TimeSeriesMethod { */ public TimeSeries getForecastWithValidParams(int countPoints) throws ModelingException { TimeSeries forecast = generateEmptyForecastPoints(originalTimeSeries, countPoints); - forecast.getFirstValue().setValue(getModel().getLastValue().getValue()); + getModel(); + forecast.getFirstValue().setValue(originalTimeSeries.getLastValue().getValue()); forecast = makeForecast(forecast); return forecast; } @@ -90,7 +91,7 @@ public abstract class TimeSeriesMethod { } } - private void validateTimeSeries() throws TimeSeriesValidateException { + protected void validateTimeSeries() throws ModelingException { if (originalTimeSeries == null || originalTimeSeries.isEmpty()) { throw new TimeSeriesValidateException("Временной ряд должен быть не пустым"); } @@ -103,6 +104,11 @@ public abstract class TimeSeriesMethod { if (originalTimeSeries.getValues().stream().anyMatch(val -> val.getDate() == null)) { throw new TimeSeriesValidateException("Временной ряд должен иметь отметки времени"); } + validateAdditionalParams(); + } + + protected void validateAdditionalParams() throws ModelingException { + } public TimeSeries getModel() throws ModelingException { diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendAddSeason.java b/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendAddSeason.java new file mode 100644 index 0000000..c493415 --- /dev/null +++ b/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendAddSeason.java @@ -0,0 +1,85 @@ +package ru.ulstu.tsMethods.exponential; + +import ru.ulstu.models.TimeSeries; +import ru.ulstu.models.exceptions.ModelingException; +import ru.ulstu.models.exceptions.TimeSeriesValidateException; +import ru.ulstu.tsMethods.TimeSeriesMethod; + +import java.util.ArrayList; +import java.util.List; + +import static ru.ulstu.tsMethods.exponential.ExponentialParamName.ALPHA; +import static ru.ulstu.tsMethods.exponential.ExponentialParamName.BETA; +import static ru.ulstu.tsMethods.exponential.ExponentialParamName.GAMMA; +import static ru.ulstu.tsMethods.exponential.ExponentialParamName.SEASON; + +public class AddTrendAddSeason extends TimeSeriesMethod { + private final ExponentialMethodParams exponentialMethodParams; + private final List sComponent = new ArrayList<>(); + private final List tComponent = new ArrayList<>(); + private final List iComponent = new ArrayList<>(); + + public AddTrendAddSeason(TimeSeries timeSeries, ExponentialMethodParams exponentialMethodParams) throws ModelingException { + super(timeSeries); + this.exponentialMethodParams = exponentialMethodParams; + } + + @Override + protected TimeSeries getModelOfValidTimeSeries() throws ModelingException { + sComponent.clear(); + tComponent.clear(); + iComponent.clear(); + iComponent.add(1.0); + sComponent.add(originalTimeSeries.getFirstValue().getValue()); + tComponent.add(0.0); + TimeSeries model = new TimeSeries("Model of " + originalTimeSeries.getName()); + model.addValue(originalTimeSeries.getFirstValue()); + //выполняется проход модели по сглаживанию + for (int t = 1; t < exponentialMethodParams.getValue(SEASON).intValue(); t++) { + sComponent.add(exponentialMethodParams.getValue(ALPHA) * originalTimeSeries.getNumericValue(t) + + (1 - exponentialMethodParams.getValue(ALPHA)) + * (sComponent.get(t - 1) + tComponent.get(t - 1))); + tComponent.add(exponentialMethodParams.getValue(BETA) + * (sComponent.get(t) - sComponent.get(t - 1)) + + (1 - exponentialMethodParams.getValue(BETA)) * tComponent.get(t - 1)); + iComponent.add(exponentialMethodParams.getValue(GAMMA) * originalTimeSeries.getNumericValue(t) / sComponent.get(sComponent.size() - 1) + + (1 - exponentialMethodParams.getValue(GAMMA)) * iComponent.get(0)); + model.addValue(originalTimeSeries.getValues().get(t), sComponent.get(sComponent.size() - 1)); + } + for (int t = exponentialMethodParams.getValue(SEASON).intValue(); + t < originalTimeSeries.getValues().size(); t++) { + sComponent.add(exponentialMethodParams.getValue(ALPHA) * originalTimeSeries.getNumericValue(t) + / iComponent.get(t - exponentialMethodParams.getValue(SEASON).intValue()) + + (1 - exponentialMethodParams.getValue(ALPHA)) + * (sComponent.get(t - 1) + tComponent.get(t - 1))); + + tComponent.add(exponentialMethodParams.getValue(BETA) + * (sComponent.get(t) - sComponent.get(t - 1)) + + (1 - exponentialMethodParams.getValue(BETA)) * tComponent.get(t - 1)); + + iComponent.add(exponentialMethodParams.getValue(GAMMA) * originalTimeSeries.getNumericValue(t) / sComponent.get(sComponent.size() - 1) + + (1 - exponentialMethodParams.getValue(GAMMA)) * iComponent.get(t - exponentialMethodParams.getValue(SEASON).intValue())); + model.addValue(originalTimeSeries.getValues().get(t), sComponent.get(sComponent.size() - 1)); + } + return model; + } + + @Override + protected void validateAdditionalParams() throws ModelingException { + if (originalTimeSeries.getLength() < exponentialMethodParams.getValue(SEASON)) { + throw new TimeSeriesValidateException("Период больше чем длина ряда"); + } + } + + @Override + protected TimeSeries makeForecast(TimeSeries forecast) throws ModelingException { + for (int t = 1; t < forecast.getLength(); t++) { + iComponent.add(exponentialMethodParams.getValue(GAMMA) * forecast.getNumericValue(t - 1) / sComponent.get(sComponent.size() - 1) + + (1 - exponentialMethodParams.getValue(GAMMA)) * iComponent.get(t + getModel().getLength() - exponentialMethodParams.getValue(SEASON).intValue())); + + forecast.getValues().get(t).setValue((sComponent.get(sComponent.size() - 1) + tComponent.get(tComponent.size() - 1) * t) + * iComponent.get(t + getModel().getLength() - exponentialMethodParams.getValue(SEASON).intValue())); + } + return forecast; + } +} diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendNoSeason.java b/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendNoSeason.java index b61f394..95d92c3 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendNoSeason.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/AddTrendNoSeason.java @@ -43,17 +43,8 @@ public class AddTrendNoSeason extends TimeSeriesMethod { } @Override - protected TimeSeries makeForecast(TimeSeries forecast) throws ModelingException { + protected TimeSeries makeForecast(TimeSeries forecast) { for (int t = 1; t < forecast.getLength(); t++) { - /*int indexOffsetForModel = t + getModel().getLength() - 2; - sComponent.add(exponentialMethodParams.getValue(ALPHA) * forecast.getNumericValue(t-1) - + (1 - exponentialMethodParams.getValue(ALPHA)) - * (sComponent.get(indexOffsetForModel) - tComponent.get(indexOffsetForModel - 1))); - - tComponent.add(exponentialMethodParams.getValue(BETA) - * (sComponent.get(indexOffsetForModel) - sComponent.get(indexOffsetForModel - 1)) - + (1 - exponentialMethodParams.getValue(BETA)) * tComponent.get(indexOffsetForModel - 1));*/ - forecast.getValues().get(t).setValue(sComponent.get(sComponent.size() - 1) + tComponent.get(tComponent.size() - 1) * t); } return forecast; diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/ExponentialMethodParams.java b/src/main/java/ru/ulstu/tsMethods/exponential/ExponentialMethodParams.java index a14a827..3446cfd 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/ExponentialMethodParams.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/ExponentialMethodParams.java @@ -27,4 +27,12 @@ public class ExponentialMethodParams { public static ExponentialMethodParams of(ExponentialParamName param1, Double value1, ExponentialParamName param2, Double value2) { return new ExponentialMethodParams(ImmutableMap.of(param1, value1, param2, value2)); } + + public static ExponentialMethodParams of(ExponentialParamName param1, Double value1, ExponentialParamName param2, Double value2, ExponentialParamName param3, Double value3) { + return new ExponentialMethodParams(ImmutableMap.of(param1, value1, param2, value2, param3, value3)); + } + + public static ExponentialMethodParams of(ExponentialParamName param1, Double value1, ExponentialParamName param2, Double value2, ExponentialParamName param3, Double value3, ExponentialParamName param4, Double value4) { + return new ExponentialMethodParams(ImmutableMap.of(param1, value1, param2, value2, param3, value3, param4, value4)); + } } diff --git a/src/main/java/ru/ulstu/tsMethods/exponential/ExponentialParamName.java b/src/main/java/ru/ulstu/tsMethods/exponential/ExponentialParamName.java index a89272a..452470f 100644 --- a/src/main/java/ru/ulstu/tsMethods/exponential/ExponentialParamName.java +++ b/src/main/java/ru/ulstu/tsMethods/exponential/ExponentialParamName.java @@ -1,5 +1,5 @@ package ru.ulstu.tsMethods.exponential; public enum ExponentialParamName { - ALPHA, BETA, GAMMA + ALPHA, BETA, GAMMA, SEASON }