#2 -- fix seasonal model
This commit is contained in:
parent
5567f4d857
commit
9e3ecc1d31
@ -2,6 +2,7 @@ plugins {
|
|||||||
id 'java'
|
id 'java'
|
||||||
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
|
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
|
||||||
id 'org.springframework.boot' version '2.3.3.RELEASE'
|
id 'org.springframework.boot' version '2.3.3.RELEASE'
|
||||||
|
id "org.sonarqube" version "2.7"
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package ru.ulstu.configurations;
|
package ru.ulstu.configuration;
|
||||||
|
|
||||||
public class ApiConfiguration {
|
public class ApiConfiguration {
|
||||||
public static final String API_1_0 = "/api/1.0/";
|
public static final String API_1_0 = "/api/1.0/";
|
@ -1,4 +1,4 @@
|
|||||||
package ru.ulstu.configurations;
|
package ru.ulstu.configuration;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
@ -1,4 +1,4 @@
|
|||||||
package ru.ulstu.configurations;
|
package ru.ulstu.configuration;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
@ -1,4 +1,4 @@
|
|||||||
package ru.ulstu.configurations;
|
package ru.ulstu.configuration;
|
||||||
|
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
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.ForecastParams;
|
||||||
import ru.ulstu.models.TimeSeries;
|
import ru.ulstu.models.TimeSeries;
|
||||||
import ru.ulstu.models.exceptions.ModelingException;
|
import ru.ulstu.models.exceptions.ModelingException;
|
||||||
|
@ -24,10 +24,10 @@ import java.time.format.DateTimeFormatter;
|
|||||||
public class IndexView implements Serializable {
|
public class IndexView implements Serializable {
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(IndexView.class);
|
private final static Logger LOG = LoggerFactory.getLogger(IndexView.class);
|
||||||
private LineChartModel model;
|
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
|
@Autowired
|
||||||
private TimeSeriesService timeSeriesService;
|
private transient TimeSeriesService timeSeriesService;
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
@ -57,7 +57,7 @@ public class IndexView implements Serializable {
|
|||||||
LineChartSeries series3 = new LineChartSeries();
|
LineChartSeries series3 = new LineChartSeries();
|
||||||
series3.setLabel("Прогноз");
|
series3.setLabel("Прогноз");
|
||||||
try {
|
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());
|
series3.set(DateTimeFormatter.ISO_LOCAL_DATE.format(value.getDate()), value.getValue());
|
||||||
}
|
}
|
||||||
} catch (ModelingException ex) {
|
} catch (ModelingException ex) {
|
||||||
|
@ -7,7 +7,7 @@ import ru.ulstu.TimeSeriesUtils;
|
|||||||
import ru.ulstu.models.TimeSeries;
|
import ru.ulstu.models.TimeSeries;
|
||||||
import ru.ulstu.models.TimeSeriesValue;
|
import ru.ulstu.models.TimeSeriesValue;
|
||||||
import ru.ulstu.models.exceptions.ModelingException;
|
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 ru.ulstu.tsMethods.exponential.ExponentialMethodParams;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
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.ALPHA;
|
||||||
import static ru.ulstu.tsMethods.exponential.ExponentialParamName.BETA;
|
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
|
@Service
|
||||||
@ -35,13 +37,15 @@ public class TimeSeriesService {
|
|||||||
|
|
||||||
public TimeSeries getForecast(TimeSeries timeSeries, int countPoints) throws ModelingException {
|
public TimeSeries getForecast(TimeSeries timeSeries, int countPoints) throws ModelingException {
|
||||||
//NoTrendNoSeason nn = new NoTrendNoSeason(ExponentialMethodParams.of(ExponentialParamName.ALPHA, 0.8));
|
//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);
|
return an.getForecast(countPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSeries smoothTimeSeries(TimeSeries timeSeries) throws ModelingException {
|
public TimeSeries smoothTimeSeries(TimeSeries timeSeries) throws ModelingException {
|
||||||
//NoTrendNoSeason nn = new NoTrendNoSeason(timeSeries, ExponentialMethodParams.of(ExponentialParamName.ALPHA, 0.8));
|
//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();
|
return an.getModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +72,7 @@ public class TimeSeriesService {
|
|||||||
return timeSeries
|
return timeSeries
|
||||||
.getValues()
|
.getValues()
|
||||||
.stream()
|
.stream()
|
||||||
.map(v -> v.getValue().toString().replaceAll("\\.", ","))
|
.map(v -> v.getValue().toString().replace("\\.", ","))
|
||||||
.collect(Collectors.joining(";"));
|
.collect(Collectors.joining(";"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,8 @@ public abstract class TimeSeriesMethod {
|
|||||||
*/
|
*/
|
||||||
public TimeSeries getForecastWithValidParams(int countPoints) throws ModelingException {
|
public TimeSeries getForecastWithValidParams(int countPoints) throws ModelingException {
|
||||||
TimeSeries forecast = generateEmptyForecastPoints(originalTimeSeries, countPoints);
|
TimeSeries forecast = generateEmptyForecastPoints(originalTimeSeries, countPoints);
|
||||||
forecast.getFirstValue().setValue(getModel().getLastValue().getValue());
|
getModel();
|
||||||
|
forecast.getFirstValue().setValue(originalTimeSeries.getLastValue().getValue());
|
||||||
forecast = makeForecast(forecast);
|
forecast = makeForecast(forecast);
|
||||||
return 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()) {
|
if (originalTimeSeries == null || originalTimeSeries.isEmpty()) {
|
||||||
throw new TimeSeriesValidateException("Временной ряд должен быть не пустым");
|
throw new TimeSeriesValidateException("Временной ряд должен быть не пустым");
|
||||||
}
|
}
|
||||||
@ -103,6 +104,11 @@ public abstract class TimeSeriesMethod {
|
|||||||
if (originalTimeSeries.getValues().stream().anyMatch(val -> val.getDate() == null)) {
|
if (originalTimeSeries.getValues().stream().anyMatch(val -> val.getDate() == null)) {
|
||||||
throw new TimeSeriesValidateException("Временной ряд должен иметь отметки времени");
|
throw new TimeSeriesValidateException("Временной ряд должен иметь отметки времени");
|
||||||
}
|
}
|
||||||
|
validateAdditionalParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void validateAdditionalParams() throws ModelingException {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSeries getModel() throws ModelingException {
|
public TimeSeries getModel() throws ModelingException {
|
||||||
|
@ -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<Double> sComponent = new ArrayList<>();
|
||||||
|
private final List<Double> tComponent = new ArrayList<>();
|
||||||
|
private final List<Double> 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;
|
||||||
|
}
|
||||||
|
}
|
@ -43,17 +43,8 @@ public class AddTrendNoSeason extends TimeSeriesMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TimeSeries makeForecast(TimeSeries forecast) throws ModelingException {
|
protected TimeSeries makeForecast(TimeSeries forecast) {
|
||||||
for (int t = 1; t < forecast.getLength(); t++) {
|
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);
|
forecast.getValues().get(t).setValue(sComponent.get(sComponent.size() - 1) + tComponent.get(tComponent.size() - 1) * t);
|
||||||
}
|
}
|
||||||
return forecast;
|
return forecast;
|
||||||
|
@ -27,4 +27,12 @@ public class ExponentialMethodParams {
|
|||||||
public static ExponentialMethodParams of(ExponentialParamName param1, Double value1, ExponentialParamName param2, Double value2) {
|
public static ExponentialMethodParams of(ExponentialParamName param1, Double value1, ExponentialParamName param2, Double value2) {
|
||||||
return new ExponentialMethodParams(ImmutableMap.of(param1, value1, param2, 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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package ru.ulstu.tsMethods.exponential;
|
package ru.ulstu.tsMethods.exponential;
|
||||||
|
|
||||||
public enum ExponentialParamName {
|
public enum ExponentialParamName {
|
||||||
ALPHA, BETA, GAMMA
|
ALPHA, BETA, GAMMA, SEASON
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user