Merge branch '9-bug-same-date' into 'master'
Resolve "Проверка ВР на одинаковые даты" Closes #9 See merge request romanov73/time-series-smoothing!8
This commit is contained in:
commit
17d21c1312
@ -14,6 +14,7 @@ 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.configuration.ApiConfiguration;
|
import ru.ulstu.configuration.ApiConfiguration;
|
||||||
|
import ru.ulstu.datamodel.exception.ModelingException;
|
||||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||||
import ru.ulstu.db.DbService;
|
import ru.ulstu.db.DbService;
|
||||||
import ru.ulstu.db.model.TimeSeriesMeta;
|
import ru.ulstu.db.model.TimeSeriesMeta;
|
||||||
@ -52,29 +53,29 @@ public class DbController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("add-time-series-set")
|
@GetMapping("add-time-series-set")
|
||||||
public void addTimeSeriesSet(@RequestParam("setKey") String setKey) {
|
public boolean addTimeSeriesSet(@RequestParam("setKey") String setKey) {
|
||||||
dbService.addSet(setKey);
|
return dbService.addSet(setKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("add-time-series")
|
@PostMapping("add-time-series")
|
||||||
public void addTimeSeries(@RequestParam("setKey") String setKey, @RequestBody TimeSeries timeSeries) throws IOException {
|
public void addTimeSeries(@RequestParam("setKey") String setKey, @RequestBody TimeSeries timeSeries) throws IOException, ModelingException {
|
||||||
dbService.addTimeSeries(new TimeSeriesSet(setKey), timeSeries);
|
dbService.addTimeSeries(new TimeSeriesSet(setKey), timeSeries);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("add-time-series-string")
|
@PostMapping("add-time-series-string")
|
||||||
public void addTimeSeries(@RequestParam("setKey") String setKey, @RequestParam("timeSeriesKey") String timeSeriesKey, @RequestBody String timeSeries) throws IOException {
|
public void addTimeSeries(@RequestParam("setKey") String setKey, @RequestParam("timeSeriesKey") String timeSeriesKey, @RequestBody String timeSeries) throws IOException, ModelingException {
|
||||||
TimeSeries timeSeriesWithKey = utilService.getTimeSeriesFromString(timeSeries);
|
TimeSeries timeSeriesWithKey = utilService.getTimeSeriesFromString(timeSeries);
|
||||||
timeSeriesWithKey.setKey(timeSeriesKey);
|
timeSeriesWithKey.setKey(timeSeriesKey);
|
||||||
dbService.addTimeSeries(new TimeSeriesSet(setKey), timeSeriesWithKey);
|
dbService.addTimeSeries(new TimeSeriesSet(setKey), timeSeriesWithKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("delete-time-series")
|
@DeleteMapping("delete-time-series")
|
||||||
public void deleteTimeSeries(@RequestParam("setKey") String setKey, @RequestParam("timeSeriesKey") String timeSeriesKey) throws IOException {
|
public boolean deleteTimeSeries(@RequestParam("setKey") String setKey, @RequestParam("timeSeriesKey") String timeSeriesKey) throws IOException {
|
||||||
dbService.deleteTimeSeries(new TimeSeriesSet(setKey), timeSeriesKey);
|
return dbService.deleteTimeSeries(new TimeSeriesSet(setKey), timeSeriesKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("delete-time-series-set")
|
@DeleteMapping("delete-time-series-set")
|
||||||
public void deleteTimeSeriesSet(@RequestParam("setKey") String setKey) throws IOException {
|
public boolean deleteTimeSeriesSet(@RequestParam("setKey") String setKey) throws IOException {
|
||||||
dbService.deleteTimeSeriesSet(new TimeSeriesSet(setKey));
|
return dbService.deleteTimeSeriesSet(new TimeSeriesSet(setKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,12 @@ package ru.ulstu.db;
|
|||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.ulstu.datamodel.exception.ModelingException;
|
||||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||||
import ru.ulstu.db.model.TimeSeriesMeta;
|
import ru.ulstu.db.model.TimeSeriesMeta;
|
||||||
import ru.ulstu.db.model.TimeSeriesSet;
|
import ru.ulstu.db.model.TimeSeriesSet;
|
||||||
import ru.ulstu.service.UtilService;
|
import ru.ulstu.service.UtilService;
|
||||||
|
import ru.ulstu.service.ValidationUtils;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
@ -72,17 +74,18 @@ public class DbFileService implements DbService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addSet(String key) {
|
public boolean addSet(String key) {
|
||||||
TimeSeriesSet timeSeriesSet = new TimeSeriesSet(key);
|
TimeSeriesSet timeSeriesSet = new TimeSeriesSet(key);
|
||||||
if (isTimeSeriesSetExists(timeSeriesSet)) {
|
if (isTimeSeriesSetExists(timeSeriesSet)) {
|
||||||
throw new RuntimeException(String.format("Time series set %s already exists", timeSeriesSet.getKey()));
|
throw new RuntimeException(String.format("Time series set %s already exists", timeSeriesSet.getKey()));
|
||||||
} else {
|
} else {
|
||||||
Paths.get(timeSeriesDbPath, timeSeriesSet.getKey()).toFile().mkdirs();
|
return Paths.get(timeSeriesDbPath, timeSeriesSet.getKey()).toFile().mkdirs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addTimeSeries(TimeSeriesSet timeSeriesSet, TimeSeries timeSeries) throws IOException {
|
public void addTimeSeries(TimeSeriesSet timeSeriesSet, TimeSeries timeSeries) throws IOException, ModelingException {
|
||||||
|
ValidationUtils.validateTimeSeries(timeSeries);
|
||||||
if (!isTimeSeriesSetExists(timeSeriesSet)) {
|
if (!isTimeSeriesSetExists(timeSeriesSet)) {
|
||||||
addSet(timeSeriesSet.getKey());
|
addSet(timeSeriesSet.getKey());
|
||||||
}
|
}
|
||||||
@ -100,16 +103,17 @@ public class DbFileService implements DbService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteTimeSeries(TimeSeriesSet set, String timeSeriesKey) throws IOException {
|
public boolean deleteTimeSeries(TimeSeriesSet set, String timeSeriesKey) throws IOException {
|
||||||
validateDb(set, timeSeriesKey);
|
validateDb(set, timeSeriesKey);
|
||||||
Files.delete(getTimeSeriesFile(set, timeSeriesKey).toPath());
|
Files.delete(getTimeSeriesFile(set, timeSeriesKey).toPath());
|
||||||
Files.delete(getTimeSeriesMetaFile(set, timeSeriesKey).toPath());
|
Files.delete(getTimeSeriesMetaFile(set, timeSeriesKey).toPath());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteTimeSeriesSet(TimeSeriesSet timeSeriesSet) {
|
public boolean deleteTimeSeriesSet(TimeSeriesSet timeSeriesSet) {
|
||||||
validateDb(timeSeriesSet);
|
validateDb(timeSeriesSet);
|
||||||
deleteDirectory(getSetPath(timeSeriesSet));
|
return deleteDirectory(getSetPath(timeSeriesSet));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateDb(TimeSeriesSet timeSeriesSet, String timeSeriesKey) {
|
private void validateDb(TimeSeriesSet timeSeriesSet, String timeSeriesKey) {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
package ru.ulstu.db;
|
package ru.ulstu.db;
|
||||||
|
|
||||||
|
import ru.ulstu.datamodel.exception.ModelingException;
|
||||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||||
import ru.ulstu.db.model.TimeSeriesMeta;
|
import ru.ulstu.db.model.TimeSeriesMeta;
|
||||||
import ru.ulstu.db.model.TimeSeriesSet;
|
import ru.ulstu.db.model.TimeSeriesSet;
|
||||||
@ -20,11 +21,11 @@ public interface DbService {
|
|||||||
|
|
||||||
TimeSeries getTimeSeries(TimeSeriesSet timeSeriesSet, String timeSeriesKey) throws IOException;
|
TimeSeries getTimeSeries(TimeSeriesSet timeSeriesSet, String timeSeriesKey) throws IOException;
|
||||||
|
|
||||||
void addSet(String key);
|
boolean addSet(String key);
|
||||||
|
|
||||||
void addTimeSeries(TimeSeriesSet timeSeriesSet, TimeSeries timeSeries) throws IOException;
|
void addTimeSeries(TimeSeriesSet timeSeriesSet, TimeSeries timeSeries) throws IOException, ModelingException;
|
||||||
|
|
||||||
void deleteTimeSeries(TimeSeriesSet set, String timeSeriesKey) throws IOException;
|
boolean deleteTimeSeries(TimeSeriesSet set, String timeSeriesKey) throws IOException;
|
||||||
|
|
||||||
void deleteTimeSeriesSet(TimeSeriesSet timeSeriesSet) throws IOException;
|
boolean deleteTimeSeriesSet(TimeSeriesSet timeSeriesSet) throws IOException;
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,9 @@ import ru.ulstu.TimeSeriesUtils;
|
|||||||
import ru.ulstu.datamodel.Model;
|
import ru.ulstu.datamodel.Model;
|
||||||
import ru.ulstu.datamodel.exception.ForecastValidateException;
|
import ru.ulstu.datamodel.exception.ForecastValidateException;
|
||||||
import ru.ulstu.datamodel.exception.ModelingException;
|
import ru.ulstu.datamodel.exception.ModelingException;
|
||||||
import ru.ulstu.datamodel.exception.TimeSeriesValidateException;
|
|
||||||
import ru.ulstu.datamodel.ts.TimeSeries;
|
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||||
import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
||||||
|
import ru.ulstu.service.ValidationUtils;
|
||||||
|
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -44,7 +44,7 @@ public abstract class Method {
|
|||||||
* @throws ModelingException генерируется, если есть проблемы моделирования при задании параметров
|
* @throws ModelingException генерируется, если есть проблемы моделирования при задании параметров
|
||||||
*/
|
*/
|
||||||
public Model getModel(TimeSeries timeSeries, List<MethodParamValue> parameters) throws ModelingException {
|
public Model getModel(TimeSeries timeSeries, List<MethodParamValue> parameters) throws ModelingException {
|
||||||
validateTimeSeries(timeSeries);
|
ValidationUtils.validateTimeSeries(timeSeries);
|
||||||
validateAdditionalParams(timeSeries, parameters);
|
validateAdditionalParams(timeSeries, parameters);
|
||||||
return getModelOfValidTimeSeries(timeSeries, parameters);
|
return getModelOfValidTimeSeries(timeSeries, parameters);
|
||||||
}
|
}
|
||||||
@ -60,7 +60,7 @@ public abstract class Method {
|
|||||||
|
|
||||||
public boolean canMakeForecast(TimeSeries timeSeries, List<MethodParamValue> parameters, int countPoints) {
|
public boolean canMakeForecast(TimeSeries timeSeries, List<MethodParamValue> parameters, int countPoints) {
|
||||||
try {
|
try {
|
||||||
validateTimeSeries(timeSeries);
|
ValidationUtils.validateTimeSeries(timeSeries);
|
||||||
validateAdditionalParams(timeSeries, parameters);
|
validateAdditionalParams(timeSeries, parameters);
|
||||||
validateForecastParams(countPoints);
|
validateForecastParams(countPoints);
|
||||||
} catch (ModelingException ex) {
|
} catch (ModelingException ex) {
|
||||||
@ -71,7 +71,7 @@ public abstract class Method {
|
|||||||
|
|
||||||
public boolean canMakeModel(TimeSeries timeSeries, List<MethodParamValue> parameters) {
|
public boolean canMakeModel(TimeSeries timeSeries, List<MethodParamValue> parameters) {
|
||||||
try {
|
try {
|
||||||
validateTimeSeries(timeSeries);
|
ValidationUtils.validateTimeSeries(timeSeries);
|
||||||
validateAdditionalParams(timeSeries, parameters);
|
validateAdditionalParams(timeSeries, parameters);
|
||||||
} catch (ModelingException ex) {
|
} catch (ModelingException ex) {
|
||||||
return false;
|
return false;
|
||||||
@ -112,21 +112,6 @@ public abstract class Method {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void validateTimeSeries(TimeSeries timeSeries) throws ModelingException {
|
|
||||||
if (timeSeries == null || timeSeries.isEmpty()) {
|
|
||||||
throw new TimeSeriesValidateException("Временной ряд должен быть не пустым");
|
|
||||||
}
|
|
||||||
if (timeSeries.getLength() < 2) {
|
|
||||||
throw new TimeSeriesValidateException("Временной ряд должен содержать хотя бы 2 точки");
|
|
||||||
}
|
|
||||||
if (timeSeries.getValues().stream().anyMatch(val -> val == null || val.getValue() == null)) {
|
|
||||||
throw new TimeSeriesValidateException("Временной ряд содержит пустые значения");
|
|
||||||
}
|
|
||||||
if (timeSeries.getValues().stream().anyMatch(val -> val.getDate() == null)) {
|
|
||||||
throw new TimeSeriesValidateException("Временной ряд должен иметь отметки времени");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void validateAdditionalParams(TimeSeries timeSeries, List<MethodParamValue> parameters) throws ModelingException {
|
protected void validateAdditionalParams(TimeSeries timeSeries, List<MethodParamValue> parameters) throws ModelingException {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
|||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public abstract class ScoreMethod {
|
public abstract class ScoreMethod {
|
||||||
private final String name;
|
private final String name;
|
||||||
@ -31,13 +32,10 @@ public abstract class ScoreMethod {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TimeSeriesValue getValueOnSameDate(TimeSeriesValue timeSeriesValueToFind, TimeSeries timeSeries) throws ModelingException {
|
protected Double getValueOnSameDate(Map<LocalDateTime, Double> tsValues, TimeSeriesValue modelValue) throws ModelingException {
|
||||||
return timeSeries.getValues()
|
return Optional.ofNullable(tsValues.get(modelValue.getDate()))
|
||||||
.stream()
|
|
||||||
.filter(v -> v.getDate().equals(timeSeriesValueToFind.getDate()))
|
|
||||||
.findAny()
|
|
||||||
.orElseThrow(() -> new ModelingException("Значение модельного ряда не найдено в оригинальном ряде: "
|
.orElseThrow(() -> new ModelingException("Значение модельного ряда не найдено в оригинальном ряде: "
|
||||||
+ timeSeriesValueToFind.getDate()
|
+ modelValue.getDate()
|
||||||
+ " " + timeSeries));
|
+ " " + tsValues));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,6 @@ import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
|||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static java.lang.Math.abs;
|
import static java.lang.Math.abs;
|
||||||
|
|
||||||
@ -25,10 +24,7 @@ public class Smape extends ScoreMethod {
|
|||||||
public Number evaluate(Map<LocalDateTime, Double> tsValues, TimeSeries model) throws ModelingException {
|
public Number evaluate(Map<LocalDateTime, Double> tsValues, TimeSeries model) throws ModelingException {
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
for (TimeSeriesValue modelValue : model.getValues()) {
|
for (TimeSeriesValue modelValue : model.getValues()) {
|
||||||
//double actualValue = getValueOnSameDate(modelValue, original).getValue();
|
double actualValue = getValueOnSameDate(tsValues, modelValue);
|
||||||
double actualValue = Optional.ofNullable(tsValues.get(modelValue.getDate()))
|
|
||||||
.orElseThrow(() -> new ModelingException("Значение модельного ряда не найдено в оригинальном ряде: "
|
|
||||||
+ modelValue.getDate()));
|
|
||||||
sum += abs(modelValue.getValue() - actualValue)
|
sum += abs(modelValue.getValue() - actualValue)
|
||||||
/ ((abs(actualValue) + abs(modelValue.getValue())) / 2);
|
/ ((abs(actualValue) + abs(modelValue.getValue())) / 2);
|
||||||
}
|
}
|
||||||
|
@ -59,8 +59,7 @@ public class MethodParamBruteForce {
|
|||||||
Method methodInstance = method.getClass().getDeclaredConstructor().newInstance();
|
Method methodInstance = method.getClass().getDeclaredConstructor().newInstance();
|
||||||
if (methodInstance.canMakeForecast(reducedTimeSeries, parametersValues, countPoints)) {
|
if (methodInstance.canMakeForecast(reducedTimeSeries, parametersValues, countPoints)) {
|
||||||
results.add(executors.submit(() -> {
|
results.add(executors.submit(() -> {
|
||||||
TimeSeries forecast = methodInstance.getForecast(reducedTimeSeries, parametersValues, countPoints);
|
TimeSeries forecast = syncDates(methodInstance.getForecast(reducedTimeSeries, parametersValues, countPoints), timeSeries);
|
||||||
forecast = syncDates(forecast, timeSeries);
|
|
||||||
return new ModelingResult(forecast, null,
|
return new ModelingResult(forecast, null,
|
||||||
parametersValues,
|
parametersValues,
|
||||||
scoreMethod.getScore(tsValues, forecast),
|
scoreMethod.getScore(tsValues, forecast),
|
||||||
|
36
src/main/java/ru/ulstu/service/ValidationUtils.java
Normal file
36
src/main/java/ru/ulstu/service/ValidationUtils.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 Anton Romanov - All Rights Reserved
|
||||||
|
* You may use, distribute and modify this code, please write to: romanov73@gmail.com.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ru.ulstu.service;
|
||||||
|
|
||||||
|
import ru.ulstu.datamodel.exception.ModelingException;
|
||||||
|
import ru.ulstu.datamodel.exception.TimeSeriesValidateException;
|
||||||
|
import ru.ulstu.datamodel.ts.TimeSeries;
|
||||||
|
import ru.ulstu.datamodel.ts.TimeSeriesValue;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
public class ValidationUtils {
|
||||||
|
public static void validateTimeSeries(TimeSeries timeSeries) throws ModelingException {
|
||||||
|
if (timeSeries == null || timeSeries.isEmpty()) {
|
||||||
|
throw new TimeSeriesValidateException("Временной ряд должен быть не пустым");
|
||||||
|
}
|
||||||
|
if (timeSeries.getLength() < 2) {
|
||||||
|
throw new TimeSeriesValidateException("Временной ряд должен содержать хотя бы 2 точки");
|
||||||
|
}
|
||||||
|
if (timeSeries.getValues().stream().anyMatch(val -> val == null || val.getValue() == null)) {
|
||||||
|
throw new TimeSeriesValidateException("Временной ряд содержит пустые значения");
|
||||||
|
}
|
||||||
|
if (timeSeries.getValues().stream().anyMatch(val -> val.getDate() == null)) {
|
||||||
|
throw new TimeSeriesValidateException("Временной ряд должен иметь отметки времени");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeSeries.getValues().stream().map(TimeSeriesValue::getDate).collect(Collectors.toSet()).size() < timeSeries.getLength()) {
|
||||||
|
throw new TimeSeriesValidateException("Временной ряд должен иметь разные отметки времени");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user