pytrendy 1.1.11.dev3__tar.gz → 1.1.11.dev4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/PKG-INFO +13 -12
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/README.md +12 -12
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pyproject.toml +1 -1
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/io/plot_pytrendy.py +1 -1
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/io/results_pytrendy.py +12 -6
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/segments_analyse.py +7 -18
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/segments_refine/artifact_cleanup.py +1 -1
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/segments_refine/trend_classify.py +1 -1
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/LICENSE +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/__init__.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/detect_trends.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/io/__init__.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/io/data/classes_signals.csv +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/io/data/series_synthetic.csv +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/io/data_loader.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/__init__.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/segments_get.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/segments_refine/__init__.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/segments_refine/abrupt_shaving.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/segments_refine/gradual_expand_contract.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/segments_refine/segment_grouping.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/segments_refine/update_neighbours.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/process_signals.py +0 -0
- {pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/simpledtw.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytrendy
|
|
3
|
-
Version: 1.1.11.
|
|
3
|
+
Version: 1.1.11.dev4
|
|
4
4
|
Summary: Trend Detection in Python. Applicable for real-world industry use cases in time series.
|
|
5
5
|
License: MIT License
|
|
6
6
|
|
|
@@ -106,20 +106,21 @@ The best detected trend is Down between dates 2025-05-09 - 2025-06-17
|
|
|
106
106
|
|
|
107
107
|
Full Results:
|
|
108
108
|
-------------------------------------------------------------------------------
|
|
109
|
-
direction start end days total_change change_rank
|
|
110
|
-
time_index
|
|
111
|
-
1 Up 2025-01-02 2025-01-24 22 14.013348 5
|
|
112
|
-
2 Down 2025-01-25 2025-02-05 11 -13.564214 6
|
|
113
|
-
3 Flat 2025-02-06 2025-02-09 3
|
|
114
|
-
4 Up 2025-02-10 2025-03-14 32 24.632035 3
|
|
115
|
-
5 Flat 2025-03-15 2025-03-17 2
|
|
116
|
-
6 Down 2025-03-18 2025-04-01 14 -22.721861 4
|
|
117
|
-
7 Up 2025-04-02 2025-05-08 36 72.611833 2
|
|
118
|
-
8 Down 2025-05-09 2025-06-17 39 -73.253968 1
|
|
119
|
-
9 Flat 2025-06-18 2025-06-30 12
|
|
109
|
+
direction start end days total_change change_rank trend_class
|
|
110
|
+
time_index
|
|
111
|
+
1 Up 2025-01-02 2025-01-24 22 14.013348 5 gradual
|
|
112
|
+
2 Down 2025-01-25 2025-02-05 11 -13.564214 6 gradual
|
|
113
|
+
3 Flat 2025-02-06 2025-02-09 3 -1.168831 9 NaN
|
|
114
|
+
4 Up 2025-02-10 2025-03-14 32 24.632035 3 gradual
|
|
115
|
+
5 Flat 2025-03-15 2025-03-17 2 5.660173 7 NaN
|
|
116
|
+
6 Down 2025-03-18 2025-04-01 14 -22.721861 4 gradual
|
|
117
|
+
7 Up 2025-04-02 2025-05-08 36 72.611833 2 gradual
|
|
118
|
+
8 Down 2025-05-09 2025-06-17 39 -73.253968 1 gradual
|
|
119
|
+
9 Flat 2025-06-18 2025-06-30 12 3.910534 8 NaN
|
|
120
120
|
-------------------------------------------------------------------------------
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
---
|
|
124
124
|
|
|
125
125
|
**Read more in the full documentation:** [russellsb.github.io/pytrendy/main](https://russellsb.github.io/pytrendy/main/)
|
|
126
|
+
|
|
@@ -49,20 +49,20 @@ The best detected trend is Down between dates 2025-05-09 - 2025-06-17
|
|
|
49
49
|
|
|
50
50
|
Full Results:
|
|
51
51
|
-------------------------------------------------------------------------------
|
|
52
|
-
direction start end days total_change change_rank
|
|
53
|
-
time_index
|
|
54
|
-
1 Up 2025-01-02 2025-01-24 22 14.013348 5
|
|
55
|
-
2 Down 2025-01-25 2025-02-05 11 -13.564214 6
|
|
56
|
-
3 Flat 2025-02-06 2025-02-09 3
|
|
57
|
-
4 Up 2025-02-10 2025-03-14 32 24.632035 3
|
|
58
|
-
5 Flat 2025-03-15 2025-03-17 2
|
|
59
|
-
6 Down 2025-03-18 2025-04-01 14 -22.721861 4
|
|
60
|
-
7 Up 2025-04-02 2025-05-08 36 72.611833 2
|
|
61
|
-
8 Down 2025-05-09 2025-06-17 39 -73.253968 1
|
|
62
|
-
9 Flat 2025-06-18 2025-06-30 12
|
|
52
|
+
direction start end days total_change change_rank trend_class
|
|
53
|
+
time_index
|
|
54
|
+
1 Up 2025-01-02 2025-01-24 22 14.013348 5 gradual
|
|
55
|
+
2 Down 2025-01-25 2025-02-05 11 -13.564214 6 gradual
|
|
56
|
+
3 Flat 2025-02-06 2025-02-09 3 -1.168831 9 NaN
|
|
57
|
+
4 Up 2025-02-10 2025-03-14 32 24.632035 3 gradual
|
|
58
|
+
5 Flat 2025-03-15 2025-03-17 2 5.660173 7 NaN
|
|
59
|
+
6 Down 2025-03-18 2025-04-01 14 -22.721861 4 gradual
|
|
60
|
+
7 Up 2025-04-02 2025-05-08 36 72.611833 2 gradual
|
|
61
|
+
8 Down 2025-05-09 2025-06-17 39 -73.253968 1 gradual
|
|
62
|
+
9 Flat 2025-06-18 2025-06-30 12 3.910534 8 NaN
|
|
63
63
|
-------------------------------------------------------------------------------
|
|
64
64
|
```
|
|
65
65
|
|
|
66
66
|
---
|
|
67
67
|
|
|
68
|
-
**Read more in the full documentation:** [russellsb.github.io/pytrendy/main](https://russellsb.github.io/pytrendy/main/)
|
|
68
|
+
**Read more in the full documentation:** [russellsb.github.io/pytrendy/main](https://russellsb.github.io/pytrendy/main/)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "pytrendy"
|
|
3
|
-
version = "1.1.11.
|
|
3
|
+
version = "1.1.11.dev4"
|
|
4
4
|
description = "Trend Detection in Python. Applicable for real-world industry use cases in time series."
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Russell Sammut Bonnici", email = "r.sammutbonnici@gmail.com" },
|
|
@@ -111,7 +111,7 @@ def plot_pytrendy(df: pd.DataFrame, value_col: str, segments_enhanced: list[dict
|
|
|
111
111
|
ax.fill_between(df.index[mask], ymin, ymax, color=color, alpha=0.4)
|
|
112
112
|
|
|
113
113
|
# Add ranking if up/down trend
|
|
114
|
-
if 'change_rank' in seg:
|
|
114
|
+
if 'change_rank' in seg and seg['direction'] in ['Up', 'Down']:
|
|
115
115
|
mid_date = start + (end - start) / 2
|
|
116
116
|
y_pos = ymax - (ymax - ymin) * 0.05
|
|
117
117
|
ax.text(mid_date, y_pos, str(seg['change_rank']), fontsize=12,
|
|
@@ -23,6 +23,8 @@ class PyTrendyResults:
|
|
|
23
23
|
List of dictionaries representing individual trend segments.
|
|
24
24
|
"""
|
|
25
25
|
self.segments = segments
|
|
26
|
+
self.trend_segments = [seg for seg in self.segments if 'trend_class' in seg] # Get segments that are trends (exclude flats and noise)
|
|
27
|
+
|
|
26
28
|
self.set_best()
|
|
27
29
|
self.set_df()
|
|
28
30
|
self.set_summary()
|
|
@@ -35,10 +37,10 @@ class PyTrendyResults:
|
|
|
35
37
|
- Identifies the best trend segment based on steepness and duration.
|
|
36
38
|
- The segment with the lowest `change_rank` is selected as the best.
|
|
37
39
|
"""
|
|
38
|
-
if len(self.
|
|
40
|
+
if len(self.trend_segments) == 0:
|
|
39
41
|
self.best = None
|
|
40
42
|
return
|
|
41
|
-
self.best = min(self.
|
|
43
|
+
self.best = min(self.trend_segments, key=lambda x: x.get('change_rank', math.inf))
|
|
42
44
|
|
|
43
45
|
def set_summary(self) -> None:
|
|
44
46
|
"""
|
|
@@ -54,19 +56,23 @@ class PyTrendyResults:
|
|
|
54
56
|
summary['df'] = pd.DataFrame()
|
|
55
57
|
return
|
|
56
58
|
|
|
59
|
+
# Count the number of segments per direction type (Up, Down, Flat, Noise)
|
|
57
60
|
direction_counts = Counter(seg["direction"] for seg in self.segments)
|
|
58
61
|
summary["direction_counts"] = dict(direction_counts)
|
|
59
62
|
|
|
60
|
-
|
|
63
|
+
# Count number of segments per trend classs (abrupt, gradual)
|
|
64
|
+
trend_class_counts = Counter(seg["trend_class"] for seg in self.trend_segments)
|
|
61
65
|
summary["trend_class_counts"] = dict(trend_class_counts)
|
|
62
66
|
|
|
63
|
-
|
|
67
|
+
# Get array of total change from trends and get max (best) total change
|
|
68
|
+
changes = [seg.get("total_change", 0) for seg in self.trend_segments]
|
|
64
69
|
summary['highest_total_change'] = np.max(changes) if len(changes) > 0 else None
|
|
65
70
|
|
|
66
71
|
# Set summary df (without extra details)
|
|
67
72
|
df = pd.DataFrame(self.segments)
|
|
68
|
-
cols = ['time_index', 'direction', 'start', 'end', 'days']
|
|
69
|
-
if len(changes) > 1:
|
|
73
|
+
cols = ['time_index', 'direction', 'start', 'end', 'days', 'total_change', 'change_rank']
|
|
74
|
+
if len(changes) > 1: # only include trend_class if atleast one trend exists
|
|
75
|
+
cols += ['trend_class']
|
|
70
76
|
df = df[cols]
|
|
71
77
|
|
|
72
78
|
df = df.set_index('time_index')
|
|
@@ -16,7 +16,7 @@ def analyse_segments(df: pd.DataFrame, value_col: str, segments: list[dict]) ->
|
|
|
16
16
|
|
|
17
17
|
Metrics added include:
|
|
18
18
|
|
|
19
|
-
- Absolute and percent change (based on
|
|
19
|
+
- Absolute and percent change (based on start/end values)
|
|
20
20
|
|
|
21
21
|
- Duration in days
|
|
22
22
|
|
|
@@ -47,19 +47,10 @@ def analyse_segments(df: pd.DataFrame, value_col: str, segments: list[dict]) ->
|
|
|
47
47
|
df_segment = df.loc[segment['start']:segment['end']]
|
|
48
48
|
|
|
49
49
|
# Calculate absolute and relative change from first point to last point of trend.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
segment_enhanced['change'] = float(val_max - val_min)
|
|
55
|
-
segment_enhanced['pct_change'] = (
|
|
56
|
-
float(val_max / val_min - 1) if val_min != 0 else np.nan
|
|
57
|
-
)
|
|
58
|
-
elif segment['direction'] == 'Down': # min - max
|
|
59
|
-
segment_enhanced['change'] = float(val_min - val_max)
|
|
60
|
-
segment_enhanced['pct_change'] = (
|
|
61
|
-
float(val_min / val_max - 1) if val_max != 0 else np.nan
|
|
62
|
-
)
|
|
50
|
+
val_start = df_segment[value_col].iloc[0]
|
|
51
|
+
val_end = df_segment[value_col].iloc[-1]
|
|
52
|
+
segment_enhanced['change'] = float(val_end - val_start)
|
|
53
|
+
segment_enhanced['pct_change'] = (float(val_end / val_start - 1) if val_start != 0 else np.nan)
|
|
63
54
|
|
|
64
55
|
# Calculate days & cumulative total change
|
|
65
56
|
days = (pd.to_datetime(segment['end']) - pd.to_datetime(segment['start'])).days
|
|
@@ -68,8 +59,7 @@ def analyse_segments(df: pd.DataFrame, value_col: str, segments: list[dict]) ->
|
|
|
68
59
|
segment_enhanced['days'] = days # set days
|
|
69
60
|
|
|
70
61
|
# Calculate cumulative total change
|
|
71
|
-
|
|
72
|
-
segment_enhanced['total_change'] = float(df_segment[value_col].diff().sum())
|
|
62
|
+
segment_enhanced['total_change'] = float(df_segment[value_col].diff().sum())
|
|
73
63
|
|
|
74
64
|
# Calculate Signal to Noise Ratio
|
|
75
65
|
signal_power = np.mean(df_segment['signal']**2)
|
|
@@ -83,8 +73,7 @@ def analyse_segments(df: pd.DataFrame, value_col: str, segments: list[dict]) ->
|
|
|
83
73
|
|
|
84
74
|
# Rank change, by steepest to shallowest change
|
|
85
75
|
sorted_segments = sorted(segments_enhanced, key=lambda x: abs(x.get('total_change', 0)), reverse=True)
|
|
86
|
-
|
|
87
|
-
for i, seg in enumerate(sorted_trends):
|
|
76
|
+
for i, seg in enumerate(sorted_segments):
|
|
88
77
|
j = seg['time_index'] - 1
|
|
89
78
|
segments_enhanced[j]['change_rank'] = int(i+1)
|
|
90
79
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pytrendy-1.1.11.dev3 → pytrendy-1.1.11.dev4}/pytrendy/post_processing/segments_refine/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|