11from typing import Iterable
22import tensorflow as tf
33import numpy as np
4- from tensorflow .data import Dataset
54import polars as pl
65import pandas as pd
76from polars ._typing import IntoExpr
@@ -24,7 +23,7 @@ def __init__(
2423 group_keys : list [str ],
2524 features : Iterable [IntoExpr ] | IntoExpr ,
2625 ) -> None :
27- self .dataframe = dataframe .drop_nulls ()
26+ self .dataframe = dataframe .drop_nulls ()[: 10000 ]
2827
2928 self .labeller = PseudoLabeller ()
3029 self .features = features
@@ -38,7 +37,6 @@ def __init__(
3837 raise Exception (
3938 f"Null values found in features: { number_of_nulls } null values"
4039 )
41-
4240 groups = (
4341 self .dataframe .select (pl .struct (group_keys ).rank ("dense" ) - 1 )
4442 .to_series ()
@@ -54,63 +52,51 @@ def __init__(
5452
5553 def to_windowed (
5654 self ,
57- stride : int = 1 ,
5855 control_frequency : float = 83 ,
5956 window_size : float = 1.5 ,
6057 window_stride : float = 0.2 ,
61- is_state_prediction : bool = False ,
58+ label_shift : int = 0 ,
6259 ) -> None :
6360 samples_per_window = int (window_size * control_frequency )
61+ self .samples_per_window = samples_per_window
6462 samples_between_windows = int (window_stride * control_frequency )
65- windows = (
66- self .dataframe [::stride ]
67- .group_by ("group" )
68- .map_groups (
69- lambda group : group .with_row_index ()
70- .cast ({"index" : pl .Int32 })
71- .group_by_dynamic (
72- index_column = "index" ,
73- every = f"{ samples_between_windows } i" ,
74- period = f"{ samples_per_window } i" ,
75- )
76- .agg ([* self .features , pl .col ("labels" )])
77- .drop ("index" )
78- .filter (self .features [0 ].list .len () == samples_per_window )
79- .select (* self .features , pl .col ("labels" ).list .last ())
80- )
63+
64+ windowed_features = pl .concat (
65+ [
66+ self .dataframe .select (
67+ generate_lags (feature , samples_per_window , "group" ),
68+ )[
69+ samples_per_window : - label_shift
70+ or None : samples_between_windows
71+ ]
72+ for feature in self .features
73+ ],
74+ how = "horizontal" ,
8175 )
82- lowest_label_count = windows .select (
83- pl .min_horizontal (
84- pl .col ("labels" )
85- .filter (pl .col ("labels" ) == 0 )
86- .len ()
87- .alias ("num_upright" ),
88- pl .col ("labels" )
89- .filter (pl .col ("labels" ) == 1 )
90- .len ()
91- .alias ("num_falling" ),
92- pl .col ("labels" )
93- .filter (pl .col ("labels" ) == 2 )
94- .len ()
95- .alias ("num_fallen" ),
96- )
97- ).item ()
98- balanced_windows = pl .concat (
99- (
100- windows .filter (pl .col ("labels" ) == 0 ).sample (
101- n = lowest_label_count
102- ),
103- windows .filter (pl .col ("labels" ) == 1 ).sample (
104- n = lowest_label_count
105- ),
106- windows .filter (pl .col ("labels" ) == 2 ).sample (
107- n = lowest_label_count
108- ),
109- )
76+
77+ shifted_labels = self .dataframe .select (
78+ pl .col ("labels" ).shift (- label_shift ).over ("group" )
79+ )[samples_per_window : - label_shift or None : samples_between_windows ]
80+
81+ windowed_dataframe = windowed_features .hstack (shifted_labels )
82+
83+ n_minority = (
84+ windowed_dataframe .get_column ("labels" )
85+ .value_counts ()
86+ .min ()
87+ .select (pl .col ("count" ))
88+ .item ()
89+ )
90+
91+ balanced_df = windowed_dataframe .group_by (
92+ "labels" , maintain_order = True
93+ ).map_groups (lambda group : group .sample (n = n_minority , seed = 1 ))
94+ balanced_df = windowed_dataframe .sample (
95+ fraction = 1 , shuffle = True , seed = 1
11096 )
111- balanced_windows = balanced_windows . sample ( fraction = 1 , shuffle = True )
112- self .input_data = balanced_windows . select ( self . features )
113- self .labels = balanced_windows .select (pl .col ("labels" ))
97+
98+ self .input_data = balanced_df . drop ( "labels" )
99+ self .labels = balanced_df .select (pl .col ("labels" ))
114100
115101 def __len__ (self ) -> int :
116102 return self .groups .unique ().numel ()
@@ -126,13 +112,18 @@ def __getitem__(self, index: int) -> tuple[tf.Tensor, tf.Tensor]:
126112 return self .input_data [mask ], self .labels [mask ]
127113
128114 def get_input_tensor (self ) -> tf .Tensor :
129- pd_df = self .input_data .to_pandas ()
115+ num_windows = len (self .input_data )
116+ window_length = self .samples_per_window
117+ num_features = len (self .features )
130118 return tf .convert_to_tensor (
131- np .array (pd_df .values .tolist ()), dtype = tf .float32
119+ np .stack ([self .input_data .to_numpy ()]).reshape (
120+ (num_windows , window_length , num_features )
121+ ),
122+ dtype = tf .float32 ,
132123 )
133124
134125 def get_labels_tensor (self ) -> tf .Tensor :
135- return tf .convert_to_tensor (self .labels .to_numpy ())
126+ return tf .convert_to_tensor (self .labels .to_numpy (), dtype = tf . float32 )
136127
137128 def get_windows_input_tensor (self ) -> list [tf .Tensor ]:
138129 windowed_input_tensor = []
@@ -142,4 +133,8 @@ def get_windows_input_tensor(self) -> list[tf.Tensor]:
142133 )
143134 return windowed_input_tensor
144135
145- # def element_spec()
136+
137+ def generate_lags (feature : pl .Expr , lags : int , group : str ) -> list [pl .Expr ]:
138+ return [
139+ feature .shift (i ).over (group ).name .suffix (str (i )) for i in range (lags )
140+ ]
0 commit comments