diff --git a/.gitignore b/.gitignore index 551dd09..34c9c58 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ htmlcov/ .pytest_cache/ tests/testtemp.py site/ +poetry.lock \ No newline at end of file diff --git a/pytrendy/io/results_pytrendy.py b/pytrendy/io/results_pytrendy.py index 11e1b96..2212128 100644 --- a/pytrendy/io/results_pytrendy.py +++ b/pytrendy/io/results_pytrendy.py @@ -35,7 +35,7 @@ def set_best(self) -> None: - Identifies the best trend segment based on steepness and duration. - The segment with the lowest `change_rank` is selected as the best. """ - if len(self.segments) == 0 or not any('change_rank' in segment for segment in self.segments): + if len(self.segments) == 0 or not any('change_rank' in segment for segment in [s for s in self.segments if s.get('direction') in ['Up', 'Down']]): self.best = None return self.best = min(self.segments, key=lambda x: x.get('change_rank', math.inf)) diff --git a/pytrendy/post_processing/segments_analyse.py b/pytrendy/post_processing/segments_analyse.py index 26308de..321d190 100644 --- a/pytrendy/post_processing/segments_analyse.py +++ b/pytrendy/post_processing/segments_analyse.py @@ -60,6 +60,12 @@ def analyse_segments(df: pd.DataFrame, value_col: str, segments: list[dict]) -> segment_enhanced['pct_change'] = ( float(val_min / val_max - 1) if val_max != 0 else np.nan ) + # I think this should capture all other segment types + else: + abs_change = float(abs(val_max - val_min)) + segment_enhanced['change'] = abs_change + mean_val = df_segment[value_col].mean() + segment_enhanced['pct_change'] = (float(abs_change / mean_val * 100) if mean_val != 0 else np.nan) # Calculate days & cumulative total change days = (pd.to_datetime(segment['end']) - pd.to_datetime(segment['start'])).days @@ -68,8 +74,7 @@ def analyse_segments(df: pd.DataFrame, value_col: str, segments: list[dict]) -> segment_enhanced['days'] = days # set days # Calculate cumulative total change - if segment['direction'] in ['Up', 'Down']: - segment_enhanced['total_change'] = float(df_segment[value_col].diff().sum()) + segment_enhanced['total_change'] = float(df_segment[value_col].diff().sum()) # Calculate Signal to Noise Ratio signal_power = np.mean(df_segment['signal']**2) @@ -83,8 +88,7 @@ def analyse_segments(df: pd.DataFrame, value_col: str, segments: list[dict]) -> # Rank change, by steepest to shallowest change sorted_segments = sorted(segments_enhanced, key=lambda x: abs(x.get('total_change', 0)), reverse=True) - sorted_trends = [seg for seg in sorted_segments if 'total_change' in seg and abs(seg['total_change']) > 0] - for i, seg in enumerate(sorted_trends): + for i, seg in enumerate(sorted_segments): j = seg['time_index'] - 1 segments_enhanced[j]['change_rank'] = int(i+1) diff --git a/pytrendy/post_processing/segments_refine/artifact_cleanup.py b/pytrendy/post_processing/segments_refine/artifact_cleanup.py index 6a09d6b..cbc9bba 100644 --- a/pytrendy/post_processing/segments_refine/artifact_cleanup.py +++ b/pytrendy/post_processing/segments_refine/artifact_cleanup.py @@ -311,11 +311,11 @@ def has_partial_overlap_prev(segment: dict, segment_prev: dict) -> bool: # Reclassify as noise if either edge cases met if too_noisy or (is_abrupt_near_noise and not trend_ends_too_close) or is_small_gradual_in_noise: segment['direction'] = 'Noise' - if 'trend_class' in segment: del segment['trend_class'] + segment['trend_class'] = 'noise' if trend_ends_too_close or trend_too_small or trend_too_flat: segment['direction'] = 'Flat' - if 'trend_class' in segment: del segment['trend_class'] + segment['trend_class'] = 'flat' segments_refined.append(segment) diff --git a/pytrendy/post_processing/segments_refine/trend_classify.py b/pytrendy/post_processing/segments_refine/trend_classify.py index 9995a01..d49d305 100644 --- a/pytrendy/post_processing/segments_refine/trend_classify.py +++ b/pytrendy/post_processing/segments_refine/trend_classify.py @@ -75,4 +75,13 @@ def classify_trends(df: pd.DataFrame, value_col: str, segments: list[dict]) -> l if segment_length < 3: segments_classified[i]['trend_class'] = 'abrupt' + for segment in segments_classified: + if 'trend_class' not in segment: + if segment['direction'] == 'Flat': + segment['trend_class'] = 'flat' + elif segment['direction'] == 'Noise': + segment['trend_class'] = 'noise' + else: + segment['trend_class'] = 'unknown' + return segments_classified