Alexandr Velikiy
6 years ago
committed by
Evgeny Smyshlyaev
12 changed files with 262 additions and 300 deletions
@ -0,0 +1,17 @@
|
||||
import utils.meta |
||||
|
||||
@utils.meta.JSONClass |
||||
class LearningInfo: |
||||
|
||||
def __init__(self): |
||||
super().__init__() |
||||
self.confidence = [] |
||||
self.patterns_list = [] |
||||
self.pattern_width = [] |
||||
self.pattern_height = [] |
||||
self.pattern_timestamp = [] |
||||
self.segment_center_list = [] |
||||
self.patterns_value = [] |
||||
|
||||
def __str__(self): |
||||
return str(self.to_json()) |
@ -1,7 +1,8 @@
|
||||
from models.model import Model, ModelState, AnalyticSegment |
||||
from models.triangle_model import TriangleModel, TriangleModelState |
||||
from models.drop_model import DropModel, DropModelState |
||||
from models.peak_model import PeakModel, PeakModelState |
||||
from models.peak_model import PeakModel |
||||
from models.jump_model import JumpModel, JumpModelState |
||||
from models.custom_model import CustomModel |
||||
from models.trough_model import TroughModel, TroughModelState |
||||
from models.trough_model import TroughModel |
||||
from models.general_model import GeneralModel, GeneralModelState |
||||
|
@ -0,0 +1,119 @@
|
||||
from analytic_types import AnalyticUnitId, TimeSeries |
||||
from analytic_types.learning_info import LearningInfo |
||||
from models import Model, ModelState, AnalyticSegment |
||||
import utils |
||||
import utils.meta |
||||
|
||||
import scipy.signal |
||||
from scipy.fftpack import fft |
||||
from typing import Optional, List, Tuple |
||||
import numpy as np |
||||
import pandas as pd |
||||
|
||||
|
||||
EXP_SMOOTHING_FACTOR = 0.01 |
||||
|
||||
|
||||
@utils.meta.JSONClass |
||||
class TriangleModelState(ModelState): |
||||
|
||||
def __init__( |
||||
self, |
||||
confidence: float = 0, |
||||
height_max: float = 0, |
||||
height_min: float = 0, |
||||
**kwargs |
||||
): |
||||
super().__init__(**kwargs) |
||||
self.confidence = confidence |
||||
self.height_max = height_max |
||||
self.height_min = height_min |
||||
|
||||
class TriangleModel(Model): |
||||
|
||||
def get_state(self, cache: Optional[dict] = None) -> TriangleModelState: |
||||
return TriangleModelState.from_json(cache) |
||||
|
||||
def do_fit( |
||||
self, |
||||
dataframe: pd.DataFrame, |
||||
labeled_segments: List[AnalyticSegment], |
||||
deleted_segments: List[AnalyticSegment], |
||||
learning_info: LearningInfo |
||||
) -> None: |
||||
data = utils.cut_dataframe(dataframe) |
||||
data = data['value'] |
||||
self.state.pattern_center = list(set(self.state.pattern_center + learning_info.segment_center_list)) |
||||
self.state.pattern_model = utils.get_av_model(learning_info.patterns_list) |
||||
convolve_list = utils.get_convolve(self.state.pattern_center, self.state.pattern_model, data, self.state.window_size) |
||||
correlation_list = utils.get_correlation(self.state.pattern_center, self.state.pattern_model, data, self.state.window_size) |
||||
height_list = learning_info.patterns_value |
||||
|
||||
del_conv_list = [] |
||||
delete_pattern_width = [] |
||||
delete_pattern_height = [] |
||||
delete_pattern_timestamp = [] |
||||
for segment in deleted_segments: |
||||
delete_pattern_timestamp.append(segment.pattern_timestamp) |
||||
deleted = utils.get_interval(data, segment.center_index, self.state.window_size) |
||||
deleted = utils.subtract_min_without_nan(deleted) |
||||
del_conv = scipy.signal.fftconvolve(deleted, self.state.pattern_model) |
||||
if len(del_conv): |
||||
del_conv_list.append(max(del_conv)) |
||||
delete_pattern_height.append(utils.find_confidence(deleted)[1]) |
||||
|
||||
self._update_fiting_result(self.state, learning_info.confidence, convolve_list, del_conv_list, height_list) |
||||
|
||||
def do_detect(self, dataframe: pd.DataFrame) -> TimeSeries: |
||||
data = utils.cut_dataframe(dataframe) |
||||
data = data['value'] |
||||
|
||||
all_extremum_indexes = self.get_extremum_indexes(data) |
||||
smoothed_data = self.get_smoothed_data(data, self.state.confidence, EXP_SMOOTHING_FACTOR) |
||||
segments = self.get_possible_segments(data, smoothed_data, all_extremum_indexes) |
||||
result = self.__filter_detection(segments, data) |
||||
result = utils.get_borders_of_peaks(result, data, self.state.window_size, self.state.confidence) |
||||
return result |
||||
|
||||
def __filter_detection(self, segments: List[int], data: pd.Series) -> list: |
||||
delete_list = [] |
||||
variance_error = self.state.window_size |
||||
close_patterns = utils.close_filtering(segments, variance_error) |
||||
segments = self.get_best_pattern(close_patterns, data) |
||||
|
||||
if len(segments) == 0 or len(self.state.pattern_model) == 0: |
||||
return [] |
||||
pattern_data = self.state.pattern_model |
||||
up_height = self.state.height_max * (1 + self.HEIGHT_ERROR) |
||||
low_height = self.state.height_min * (1 - self.HEIGHT_ERROR) |
||||
up_conv = self.state.convolve_max * (1 + 1.5 * self.CONV_ERROR) |
||||
low_conv = self.state.convolve_min * (1 - self.CONV_ERROR) |
||||
up_del_conv = self.state.conv_del_max * (1 + self.DEL_CONV_ERROR) |
||||
low_del_conv = self.state.conv_del_min * (1 - self.DEL_CONV_ERROR) |
||||
for segment in segments: |
||||
if segment > self.state.window_size: |
||||
convol_data = utils.get_interval(data, segment, self.state.window_size) |
||||
convol_data = utils.subtract_min_without_nan(convol_data) |
||||
percent_of_nans = convol_data.isnull().sum() / len(convol_data) |
||||
if percent_of_nans > 0.5: |
||||
delete_list.append(segment) |
||||
continue |
||||
elif 0 < percent_of_nans <= 0.5: |
||||
nan_list = utils.find_nan_indexes(convol_data) |
||||
convol_data = utils.nan_to_zero(convol_data, nan_list) |
||||
pattern_data = utils.nan_to_zero(pattern_data, nan_list) |
||||
conv = scipy.signal.fftconvolve(convol_data, pattern_data) |
||||
pattern_height = convol_data.values.max() |
||||
if pattern_height > up_height or pattern_height < low_height: |
||||
delete_list.append(segment) |
||||
continue |
||||
if max(conv) > up_conv or max(conv) < low_conv: |
||||
delete_list.append(segment) |
||||
continue |
||||
if max(conv) < up_del_conv and max(conv) > low_del_conv: |
||||
delete_list.append(segment) |
||||
else: |
||||
delete_list.append(segment) |
||||
for item in delete_list: |
||||
segments.remove(item) |
||||
return set(segments) |
Loading…
Reference in new issue