def create_transformation(self) -> Transformation: remove_field_names = [] if not self.use_feat_static_real: remove_field_names.append(FieldName.FEAT_STATIC_REAL) if not self.use_feat_dynamic_real: remove_field_names.append(FieldName.FEAT_DYNAMIC_REAL) if not self.use_feat_dynamic_cat: remove_field_names.append(FieldName.FEAT_DYNAMIC_CAT) return Chain( [RemoveFields(field_names=remove_field_names)] + ([SetField(output_field=FieldName.FEAT_STATIC_CAT, value=[0] )] if not self.use_feat_static_cat else []) + ([SetField(output_field=FieldName.FEAT_STATIC_REAL, value=[0.0] )] if not self.use_feat_static_real else []) + [ AsNumpyArray( field=FieldName.FEAT_STATIC_CAT, expected_ndim=1, dtype=np.long, ), AsNumpyArray( field=FieldName.FEAT_STATIC_REAL, expected_ndim=1, dtype=self.dtype, ), AsNumpyArray( field=FieldName.TARGET, # in the following line, we add 1 for the time dimension expected_ndim=1 + len(self.distr_output.event_shape), dtype=self.dtype, ), AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, dtype=self.dtype, ), AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=self.time_features, pred_length=self.prediction_length, ), AddAgeFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_AGE, pred_length=self.prediction_length, log_scale=True, dtype=self.dtype, ), VstackFeatures( output_field=FieldName.FEAT_TIME, input_fields=[FieldName.FEAT_TIME, FieldName.FEAT_AGE] + ([FieldName.FEAT_DYNAMIC_REAL] if self. use_feat_dynamic_real else []) + ([FieldName.FEAT_DYNAMIC_CAT] if self. use_feat_dynamic_cat else []), ), ])
def create_transformation(self) -> Transformation: remove_field_names = [FieldName.FEAT_DYNAMIC_CAT] if not self.use_feat_static_real: remove_field_names.append(FieldName.FEAT_STATIC_REAL) if not self.use_feat_dynamic_real: remove_field_names.append(FieldName.FEAT_DYNAMIC_REAL) return Chain( [RemoveFields(field_names=remove_field_names)] + ([SetField(output_field=FieldName.FEAT_STATIC_CAT, value=[0.0] )] if not self.use_feat_static_cat else []) + ([SetField(output_field=FieldName.FEAT_STATIC_REAL, value=[0.0] )] if not self.use_feat_static_real else []) + [ AsNumpyArray(field=FieldName.FEAT_STATIC_CAT, expected_ndim=1), AsNumpyArray(field=FieldName.FEAT_STATIC_REAL, expected_ndim=1), AsNumpyArray( field=FieldName.TARGET, # in the following line, we add 1 for the time dimension expected_ndim=1 + len(self.distr_output.event_shape), ), AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, ), AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=self.time_features, pred_length=self.prediction_length, ), AddAgeFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_AGE, pred_length=self.prediction_length, log_scale=True, ), VstackFeatures( output_field=FieldName.FEAT_TIME, input_fields=[FieldName.FEAT_TIME, FieldName.FEAT_AGE] + ([FieldName.FEAT_DYNAMIC_REAL] if self. use_feat_dynamic_real else []), ), InstanceSplitter( target_field=FieldName.TARGET, is_pad_field=FieldName.IS_PAD, start_field=FieldName.START, forecast_start_field=FieldName.FORECAST_START, train_sampler=ExpectedNumInstanceSampler(num_instances=1), past_length=self.history_length, future_length=self.prediction_length, time_series_fields=[ FieldName.FEAT_TIME, FieldName.OBSERVED_VALUES, ], ), ])
def create_transformation(self) -> Transformation: remove_field_names = [FieldName.FEAT_DYNAMIC_CAT] if not self.use_feat_dynamic_real: remove_field_names.append(FieldName.FEAT_DYNAMIC_REAL) if not self.use_feat_static_real: remove_field_names.append(FieldName.FEAT_STATIC_REAL) return Chain([RemoveFields(field_names=remove_field_names)] + ( [SetField(output_field=FieldName.FEAT_STATIC_CAT, value=[0] )] if not self.use_feat_static_cat else [] ) + ([SetField( output_field=FieldName.FEAT_STATIC_REAL, value=[0.0] )] if not self.use_feat_static_real else []) + [ AsNumpyArray( field=FieldName .TARGET, expected_ndim=1 + len(self.distr_output .event_shape), ), # maps the target to (1, T) # if the target data is uni dimensional ExpandDimArray( field=FieldName.TARGET, axis=0 if self.distr_output.event_shape[0] == 1 else None, ), AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, ), AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=self.time_features, pred_length=self.prediction_length, ), AddAgeFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_AGE, pred_length=self.prediction_length, log_scale=True, ), VstackFeatures( output_field=FieldName.FEAT_TIME, input_fields=[FieldName.FEAT_TIME, FieldName.FEAT_AGE] + ([FieldName.FEAT_DYNAMIC_REAL] if self. use_feat_dynamic_real else []), ), TargetDimIndicator( field_name="target_dimension_indicator", target_field=FieldName.TARGET, ), AsNumpyArray(field=FieldName.FEAT_STATIC_CAT, expected_ndim=1, dtype=np.long), AsNumpyArray(field=FieldName.FEAT_STATIC_REAL, expected_ndim=1), ])
def create_transformation(self) -> Transformation: remove_field_names = [ FieldName.FEAT_DYNAMIC_CAT, FieldName.FEAT_STATIC_REAL, ] if not self.use_feat_dynamic_real: remove_field_names.append(FieldName.FEAT_DYNAMIC_REAL) return Chain( [RemoveFields(field_names=remove_field_names)] + ( [SetField(output_field=FieldName.FEAT_STATIC_CAT, value=[0.0])] if not self.use_feat_static_cat else [] ) + [ AsNumpyArray(field=FieldName.FEAT_STATIC_CAT, expected_ndim=1), AsNumpyArray(field=FieldName.TARGET, expected_ndim=1), # gives target the (1, T) layout ExpandDimArray(field=FieldName.TARGET, axis=0), AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, ), # Unnormalized seasonal features AddTimeFeatures( time_features=self.issm.time_features(), pred_length=self.prediction_length, start_field=FieldName.START, target_field=FieldName.TARGET, output_field=SEASON_INDICATORS_FIELD, ), AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=self.time_features, pred_length=self.prediction_length, ), AddAgeFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_AGE, pred_length=self.prediction_length, log_scale=True, ), VstackFeatures( output_field=FieldName.FEAT_TIME, input_fields=[FieldName.FEAT_TIME, FieldName.FEAT_AGE] + ( [FieldName.FEAT_DYNAMIC_REAL] if self.use_feat_dynamic_real else [] ), ), ] )
def create_transformation(self) -> Transformation: remove_field_names = [ FieldName.FEAT_DYNAMIC_CAT, FieldName.FEAT_STATIC_REAL, ] if not self.use_feat_dynamic_real: remove_field_names.append(FieldName.FEAT_DYNAMIC_REAL) return Chain( [RemoveFields(field_names=remove_field_names)] + ( [SetField(output_field=FieldName.FEAT_STATIC_CAT, value=[0.0])] if not self.use_feat_static_cat else [] ) + [ AsNumpyArray(field=FieldName.FEAT_STATIC_CAT, expected_ndim=1), AsNumpyArray(field=FieldName.TARGET, expected_ndim=1), # gives target the (1, T) layout ExpandDimArray(field=FieldName.TARGET, axis=0), AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, ), # Unnormalized seasonal features AddTimeFeatures( time_features=CompositeISSM.seasonal_features(self.freq), pred_length=self.prediction_length, start_field=FieldName.START, target_field=FieldName.TARGET, output_field=SEASON_INDICATORS_FIELD, ), AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=self.time_features, pred_length=self.prediction_length, ), AddAgeFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_AGE, pred_length=self.prediction_length, log_scale=True, ), VstackFeatures( output_field=FieldName.FEAT_TIME, input_fields=[FieldName.FEAT_TIME, FieldName.FEAT_AGE] + ( [FieldName.FEAT_DYNAMIC_REAL] if self.use_feat_dynamic_real else [] ), ), CanonicalInstanceSplitter( target_field=FieldName.TARGET, is_pad_field=FieldName.IS_PAD, start_field=FieldName.START, forecast_start_field=FieldName.FORECAST_START, instance_sampler=TestSplitSampler(), time_series_fields=[ FieldName.FEAT_TIME, SEASON_INDICATORS_FIELD, FieldName.OBSERVED_VALUES, ], allow_target_padding=True, instance_length=self.past_length, use_prediction_features=True, prediction_length=self.prediction_length, ), ] )
def create_transformation(self) -> Transformation: transforms = ([AsNumpyArray(field=FieldName.TARGET, expected_ndim=1)] + ([ AsNumpyArray(field=name, expected_ndim=1) for name in self.static_cardinalities.keys() ]) + [ AsNumpyArray(field=name, expected_ndim=1) for name in chain( self.static_feature_dims.keys(), self.dynamic_cardinalities.keys(), ) ] + [ AsNumpyArray(field=name, expected_ndim=2) for name in self.dynamic_feature_dims.keys() ] + [ AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, ), AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=self.time_features, pred_length=self.prediction_length, ), ]) if self.static_cardinalities: transforms.append( VstackFeatures( output_field=FieldName.FEAT_STATIC_CAT, input_fields=list(self.static_cardinalities.keys()), h_stack=True, )) else: transforms.extend([ SetField( output_field=FieldName.FEAT_STATIC_CAT, value=[0.0], ), AsNumpyArray(field=FieldName.FEAT_STATIC_CAT, expected_ndim=1), ]) if self.static_feature_dims: transforms.append( VstackFeatures( output_field=FieldName.FEAT_STATIC_REAL, input_fields=list(self.static_feature_dims.keys()), h_stack=True, )) else: transforms.extend([ SetField( output_field=FieldName.FEAT_STATIC_REAL, value=[0.0], ), AsNumpyArray(field=FieldName.FEAT_STATIC_REAL, expected_ndim=1), ]) if self.dynamic_cardinalities: transforms.append( VstackFeatures( output_field=FieldName.FEAT_DYNAMIC_CAT, input_fields=list(self.dynamic_cardinalities.keys()), )) else: transforms.extend([ SetField( output_field=FieldName.FEAT_DYNAMIC_CAT, value=[[0.0]], ), AsNumpyArray( field=FieldName.FEAT_DYNAMIC_CAT, expected_ndim=2, ), BroadcastTo( field=FieldName.FEAT_DYNAMIC_CAT, ext_length=self.prediction_length, ), ]) input_fields = [FieldName.FEAT_TIME] if self.dynamic_feature_dims: input_fields += list(self.dynamic_feature_dims.keys()) transforms.append( VstackFeatures( input_fields=input_fields, output_field=FieldName.FEAT_DYNAMIC_REAL, )) if self.past_dynamic_cardinalities: transforms.append( VstackFeatures( output_field=FieldName.PAST_FEAT_DYNAMIC + "_cat", input_fields=list(self.past_dynamic_cardinalities.keys()), )) else: transforms.extend([ SetField( output_field=FieldName.PAST_FEAT_DYNAMIC + "_cat", value=[[0.0]], ), AsNumpyArray( field=FieldName.PAST_FEAT_DYNAMIC + "_cat", expected_ndim=2, ), BroadcastTo(field=FieldName.PAST_FEAT_DYNAMIC + "_cat"), ]) if self.past_dynamic_feature_dims: transforms.append( VstackFeatures( output_field=FieldName.PAST_FEAT_DYNAMIC_REAL, input_fields=list(self.past_dynamic_feature_dims.keys()), )) else: transforms.extend([ SetField( output_field=FieldName.PAST_FEAT_DYNAMIC_REAL, value=[[0.0]], ), AsNumpyArray(field=FieldName.PAST_FEAT_DYNAMIC_REAL, expected_ndim=2), BroadcastTo(field=FieldName.PAST_FEAT_DYNAMIC_REAL), ]) return Chain(transforms)
def create_transformation(self) -> Transformation: chain = [] dynamic_feat_fields = [] remove_field_names = [ FieldName.FEAT_DYNAMIC_CAT, FieldName.FEAT_STATIC_REAL, ] # --- GENERAL TRANSFORMATION CHAIN --- # determine unused input if not self.use_past_feat_dynamic_real: remove_field_names.append(FieldName.PAST_FEAT_DYNAMIC_REAL) if not self.use_feat_dynamic_real: remove_field_names.append(FieldName.FEAT_DYNAMIC_REAL) if not self.use_feat_static_cat: remove_field_names.append(FieldName.FEAT_STATIC_CAT) chain.extend( [ RemoveFields(field_names=remove_field_names), AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, dtype=self.dtype, ), ] ) # --- TRANSFORMATION CHAIN FOR DYNAMIC FEATURES --- if self.add_time_feature: chain.append( AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=time_features_from_frequency_str(self.freq), pred_length=self.prediction_length, dtype=self.dtype, ) ) dynamic_feat_fields.append(FieldName.FEAT_TIME) if self.add_age_feature: chain.append( AddAgeFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_AGE, pred_length=self.prediction_length, dtype=self.dtype, ) ) dynamic_feat_fields.append(FieldName.FEAT_AGE) if self.use_feat_dynamic_real: # Backwards compatibility: chain.append( RenameFields({"dynamic_feat": FieldName.FEAT_DYNAMIC_REAL}) ) dynamic_feat_fields.append(FieldName.FEAT_DYNAMIC_REAL) # we need to make sure that there is always some dynamic input # we will however disregard it in the hybrid forward. # the time feature is empty for yearly freq so also adding a dummy feature # in the case that the time feature is the only one on if len(dynamic_feat_fields) == 0 or ( not self.add_age_feature and not self.use_feat_dynamic_real and self.freq == "Y" ): chain.append( AddConstFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_CONST, pred_length=self.prediction_length, const=0.0, # For consistency in case with no dynamic features dtype=self.dtype, ) ) dynamic_feat_fields.append(FieldName.FEAT_CONST) # now we map all the dynamic input of length context_length + prediction_length onto FieldName.FEAT_DYNAMIC # we exclude past_feat_dynamic_real since its length is only context_length if len(dynamic_feat_fields) > 1: chain.append( VstackFeatures( output_field=FieldName.FEAT_DYNAMIC, input_fields=dynamic_feat_fields, ) ) elif len(dynamic_feat_fields) == 1: chain.append( RenameFields({dynamic_feat_fields[0]: FieldName.FEAT_DYNAMIC}) ) # --- TRANSFORMATION CHAIN FOR STATIC FEATURES --- if not self.use_feat_static_cat: chain.append( SetField( output_field=FieldName.FEAT_STATIC_CAT, value=np.array([0], dtype=np.int32), ) ) # --- SAMPLE AND CUT THE TIME-SERIES --- chain.append( # because of how the forking decoder works, every time step # in context is used for splitting, which is why we use the TestSplitSampler ForkingSequenceSplitter( train_sampler=TestSplitSampler(), enc_len=self.context_length, dec_len=self.prediction_length, num_forking=self.num_forking, encoder_series_fields=[ FieldName.OBSERVED_VALUES, # RTS with past and future values which is never empty because added dummy constant variable FieldName.FEAT_DYNAMIC, ] + ( # RTS with only past values are only used by the encoder [FieldName.PAST_FEAT_DYNAMIC_REAL] if self.use_past_feat_dynamic_real else [] ), encoder_disabled_fields=( [FieldName.FEAT_DYNAMIC] if not self.enable_encoder_dynamic_feature else [] ) + ( [FieldName.PAST_FEAT_DYNAMIC_REAL] if not self.enable_encoder_dynamic_feature and self.use_past_feat_dynamic_real else [] ), decoder_series_fields=[ FieldName.OBSERVED_VALUES, # Decoder will use all fields under FEAT_DYNAMIC which are the RTS with past and future values FieldName.FEAT_DYNAMIC, ], decoder_disabled_fields=( [FieldName.FEAT_DYNAMIC] if not self.enable_decoder_dynamic_feature else [] ), prediction_time_decoder_exclude=[FieldName.OBSERVED_VALUES], ) ) # past_feat_dynamic features generated above in ForkingSequenceSplitter from those under feat_dynamic - we need # to stack with the other short related time series from the system labeled as past_past_feat_dynamic_real. # The system labels them as past_feat_dynamic_real and the additional past_ is added to the string # in the ForkingSequenceSplitter if self.use_past_feat_dynamic_real: # Stack features from ForkingSequenceSplitter horizontally since they were transposed # so shape is now (enc_len, num_past_feature_dynamic) chain.append( VstackFeatures( output_field=FieldName.PAST_FEAT_DYNAMIC, input_fields=[ "past_" + FieldName.PAST_FEAT_DYNAMIC_REAL, FieldName.PAST_FEAT_DYNAMIC, ], h_stack=True, ) ) return Chain(chain)
def create_transformation(self) -> Transformation: chain = [] dynamic_feat_fields = [] remove_field_names = [ FieldName.FEAT_DYNAMIC_CAT, FieldName.FEAT_STATIC_REAL, ] # --- GENERAL TRANSFORMATION CHAIN --- # determine unused input if not self.use_past_feat_dynamic_real: remove_field_names.append(FieldName.PAST_FEAT_DYNAMIC_REAL) if not self.use_feat_dynamic_real: remove_field_names.append(FieldName.FEAT_DYNAMIC_REAL) if not self.use_feat_static_cat: remove_field_names.append(FieldName.FEAT_STATIC_CAT) chain.extend( [ RemoveFields(field_names=remove_field_names), AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, dtype=self.dtype, ), ] ) # --- TRANSFORMATION CHAIN FOR DYNAMIC FEATURES --- if self.add_time_feature: chain.append( AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=time_features_from_frequency_str(self.freq), pred_length=self.prediction_length, dtype=self.dtype, ) ) dynamic_feat_fields.append(FieldName.FEAT_TIME) if self.add_age_feature: chain.append( AddAgeFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_AGE, pred_length=self.prediction_length, dtype=self.dtype, ) ) dynamic_feat_fields.append(FieldName.FEAT_AGE) if self.use_feat_dynamic_real: # Backwards compatibility: chain.append( RenameFields({"dynamic_feat": FieldName.FEAT_DYNAMIC_REAL}) ) dynamic_feat_fields.append(FieldName.FEAT_DYNAMIC_REAL) # we need to make sure that there is always some dynamic input # we will however disregard it in the hybrid forward. # the time feature is empty for yearly freq so also adding a dummy feature # in the case that the time feature is the only one on if len(dynamic_feat_fields) == 0 or ( not self.add_age_feature and not self.use_feat_dynamic_real and self.freq == "Y" ): chain.append( AddConstFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_CONST, pred_length=self.prediction_length, const=0.0, # For consistency in case with no dynamic features dtype=self.dtype, ) ) dynamic_feat_fields.append(FieldName.FEAT_CONST) # now we map all the dynamic input of length context_length + prediction_length onto FieldName.FEAT_DYNAMIC # we exclude past_feat_dynamic_real since its length is only context_length if len(dynamic_feat_fields) > 1: chain.append( VstackFeatures( output_field=FieldName.FEAT_DYNAMIC, input_fields=dynamic_feat_fields, ) ) elif len(dynamic_feat_fields) == 1: chain.append( RenameFields({dynamic_feat_fields[0]: FieldName.FEAT_DYNAMIC}) ) # --- TRANSFORMATION CHAIN FOR STATIC FEATURES --- if not self.use_feat_static_cat: chain.append( SetField( output_field=FieldName.FEAT_STATIC_CAT, value=np.array([0], dtype=np.int32), ) ) return Chain(chain)
def create_transformation(self) -> Transformation: transforms = [] if self.use_feat_dynamic_real: transforms.append( AsNumpyArray( field=FieldName.FEAT_DYNAMIC_REAL, expected_ndim=2, )) else: transforms.extend([ SetField( output_field=FieldName.FEAT_DYNAMIC_REAL, value=[[]] * (self.context_length + self.prediction_length), ), AsNumpyArray( field=FieldName.FEAT_DYNAMIC_REAL, expected_ndim=2, ), # SwapAxes(input_fields=[FieldName.FEAT_DYNAMIC_REAL], axes=(0,1)), ]) if self.use_feat_dynamic_cat: transforms.append( AsNumpyArray( field=FieldName.FEAT_DYNAMIC_CAT, expected_ndim=2, )) else: # Manually set dummy dynamic categorical features and split by time # Unknown issue in dataloader if leave splitting to InstanceSplitter transforms.extend([ SetField( output_field="past_" + FieldName.FEAT_DYNAMIC_CAT, value=[[]] * self.context_length, ), AsNumpyArray( field="past_" + FieldName.FEAT_DYNAMIC_CAT, expected_ndim=2, ), SetField( output_field="future_" + FieldName.FEAT_DYNAMIC_CAT, value=[[]] * self.prediction_length, ), AsNumpyArray( field="future_" + FieldName.FEAT_DYNAMIC_CAT, expected_ndim=2, ), ]) if self.use_feat_static_real: transforms.append( AsNumpyArray( field=FieldName.FEAT_STATIC_REAL, expected_ndim=1, )) else: transforms.extend([ SetField( output_field=FieldName.FEAT_STATIC_REAL, value=[], ), AsNumpyArray( field=FieldName.FEAT_STATIC_REAL, expected_ndim=1, ), ]) if self.use_feat_static_cat: transforms.append( AsNumpyArray( field=FieldName.FEAT_STATIC_CAT, expected_ndim=1, )) time_series_fields = [FieldName.OBSERVED_VALUES] if self.use_feat_dynamic_cat: time_series_fields.append(FieldName.FEAT_DYNAMIC_CAT) if self.use_feat_dynamic_real or (self.time_features is not None): time_series_fields.append(FieldName.FEAT_DYNAMIC_REAL) transforms.extend([ AsNumpyArray(field=FieldName.TARGET, expected_ndim=1), AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, ), AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=self.time_features, pred_length=self.prediction_length, ), AddAgeFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_AGE, pred_length=self.prediction_length, log_scale=True, ), VstackFeatures( output_field=FieldName.FEAT_DYNAMIC_REAL, input_fields=[FieldName.FEAT_TIME, FieldName.FEAT_AGE] + ([FieldName.FEAT_DYNAMIC_REAL] if self.use_feat_dynamic_real else []), ), InstanceSplitter( target_field=FieldName.TARGET, is_pad_field=FieldName.IS_PAD, start_field=FieldName.START, forecast_start_field=FieldName.FORECAST_START, train_sampler=self.train_sampler, past_length=self.context_length, future_length=self.prediction_length, time_series_fields=time_series_fields, pick_incomplete=True, ), ]) return Chain(transforms)
def create_input_transform( is_train, prediction_length, past_length, use_feat_static_cat, use_feat_dynamic_real, freq, time_features, extract_tail_chunks_for_train: bool = False, ): SEASON_INDICATORS_FIELD = "seasonal_indicators" remove_field_names = [ FieldName.FEAT_DYNAMIC_CAT, FieldName.FEAT_STATIC_REAL, ] if not use_feat_dynamic_real: remove_field_names.append(FieldName.FEAT_DYNAMIC_REAL) time_features = ( time_features if time_features is not None else time_features_from_frequency_str(freq) ) transform = Chain( [RemoveFields(field_names=remove_field_names)] + ( [SetField(output_field=FieldName.FEAT_STATIC_CAT, value=[0.0])] if not use_feat_static_cat else [] ) + [ AsNumpyArray(field=FieldName.FEAT_STATIC_CAT, expected_ndim=1), AsNumpyArray(field=FieldName.TARGET, expected_ndim=1), # gives target the (1, T) layout ExpandDimArray(field=FieldName.TARGET, axis=0), AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, ), # Unnormalized seasonal features AddTimeFeatures( time_features=CompositeISSM.seasonal_features(freq), pred_length=prediction_length, start_field=FieldName.START, target_field=FieldName.TARGET, output_field=SEASON_INDICATORS_FIELD, ), AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=time_features, pred_length=prediction_length, ), AddAgeFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_AGE, pred_length=prediction_length, log_scale=True, ), VstackFeatures( output_field=FieldName.FEAT_TIME, input_fields=[FieldName.FEAT_TIME, FieldName.FEAT_AGE] + ( [FieldName.FEAT_DYNAMIC_REAL] if use_feat_dynamic_real else [] ), ), CanonicalInstanceSplitter( target_field=FieldName.TARGET, is_pad_field=FieldName.IS_PAD, start_field=FieldName.START, forecast_start_field=FieldName.FORECAST_START, instance_sampler=ExpectedNumInstanceSampler(num_instances=1), time_series_fields=[ FieldName.FEAT_TIME, SEASON_INDICATORS_FIELD, FieldName.OBSERVED_VALUES, ], allow_target_padding=True, instance_length=past_length, use_prediction_features=True, prediction_length=prediction_length, ) if (is_train and not extract_tail_chunks_for_train) else CanonicalInstanceSplitter( target_field=FieldName.TARGET, is_pad_field=FieldName.IS_PAD, start_field=FieldName.START, forecast_start_field=FieldName.FORECAST_START, instance_sampler=TestSplitSampler(), time_series_fields=[ FieldName.FEAT_TIME, SEASON_INDICATORS_FIELD, FieldName.OBSERVED_VALUES, ], allow_target_padding=True, instance_length=past_length, use_prediction_features=True, prediction_length=prediction_length, ), ] ) return transform
def create_transformation(self) -> Transformation: transforms = ([AsNumpyArray(field=FieldName.TARGET, expected_ndim=1)] + ([ AsNumpyArray(field=name, expected_ndim=1) for name in self.static_cardinalities.keys() ]) + [ AsNumpyArray(field=name, expected_ndim=1) for name in chain( self.static_feature_dims.keys(), self.dynamic_cardinalities.keys(), ) ] + [ AsNumpyArray(field=name, expected_ndim=2) for name in self.dynamic_feature_dims.keys() ] + [ AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, ), AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=self.time_features, pred_length=self.prediction_length, ), ]) ts_fields = [] past_ts_fields = [] if self.static_cardinalities: transforms.append( VstackFeatures( output_field=FieldName.FEAT_STATIC_CAT, input_fields=list(self.static_cardinalities.keys()), )) else: transforms.extend([ SetField( output_field=FieldName.FEAT_STATIC_CAT, value=[0.0], ), AsNumpyArray(field=FieldName.FEAT_STATIC_CAT, expected_ndim=1), ]) if self.static_feature_dims: transforms.append( VstackFeatures( output_field=FieldName.FEAT_STATIC_REAL, input_fields=list(self.static_feature_dims.keys()), )) else: transforms.extend([ SetField( output_field=FieldName.FEAT_STATIC_REAL, value=[0.0], ), AsNumpyArray(field=FieldName.FEAT_STATIC_REAL, expected_ndim=1), ]) if self.dynamic_cardinalities: transforms.append( VstackFeatures( output_field=FieldName.FEAT_DYNAMIC_CAT, input_fields=list(self.dynamic_cardinalities.keys()), )) ts_fields.append(FieldName.FEAT_DYNAMIC_CAT) else: transforms.extend([ SetField( output_field=FieldName.FEAT_DYNAMIC_CAT, value=[0.0], ), AsNumpyArray(field=FieldName.FEAT_DYNAMIC_CAT, expected_ndim=1), ]) input_fields = [FieldName.FEAT_TIME] if self.dynamic_feature_dims: input_fields += list(self.dynamic_feature_dims.keys()) transforms.append( VstackFeatures( input_fields=input_fields, output_field=FieldName.FEAT_DYNAMIC_REAL, )) ts_fields.append(FieldName.FEAT_DYNAMIC_REAL) if self.past_dynamic_cardinalities: transforms.append( VstackFeatures( output_field=FieldName.PAST_FEAT_DYNAMIC + "_cat", input_fields=list(self.past_dynamic_cardinalities.keys()), )) past_ts_fields.append(FieldName.PAST_FEAT_DYNAMIC + "_cat") else: transforms.extend([ SetField( output_field=FieldName.PAST_FEAT_DYNAMIC + "_cat", value=[0.0], ), AsNumpyArray( field=FieldName.PAST_FEAT_DYNAMIC + "_cat", expected_ndim=1, ), ]) if self.past_dynamic_feature_dims: transforms.append( VstackFeatures( output_field=FieldName.PAST_FEAT_DYNAMIC_REAL, input_fields=list(self.past_dynamic_feature_dims.keys()), )) past_ts_fields.append(FieldName.PAST_FEAT_DYNAMIC_REAL) else: transforms.extend([ SetField( output_field=FieldName.PAST_FEAT_DYNAMIC_REAL, value=[[0.0]], ), AsNumpyArray(field=FieldName.PAST_FEAT_DYNAMIC_REAL, expected_ndim=2), ]) transforms.append( TFTInstanceSplitter( train_sampler=ExpectedNumInstanceSampler( num_instances=self.num_instance_per_series, ), past_length=self.context_length, future_length=self.prediction_length, time_series_fields=ts_fields, past_time_series_fields=past_ts_fields, )) return Chain(transforms)
def create_transformation(self) -> Transformation: chain = [] dynamic_feat_fields = [] remove_field_names = [ FieldName.FEAT_DYNAMIC_CAT, FieldName.FEAT_STATIC_REAL, ] # --- GENERAL TRANSFORMATION CHAIN --- # determine unused input if not self.use_feat_dynamic_real: remove_field_names.append(FieldName.FEAT_DYNAMIC_REAL) if not self.use_feat_static_cat: remove_field_names.append(FieldName.FEAT_STATIC_CAT) chain.extend([ RemoveFields(field_names=remove_field_names), AddObservedValuesIndicator( target_field=FieldName.TARGET, output_field=FieldName.OBSERVED_VALUES, dtype=self.dtype, ), ]) # --- TRANSFORMATION CHAIN FOR DYNAMIC FEATURES --- if self.add_time_feature: chain.append( AddTimeFeatures( start_field=FieldName.START, target_field=FieldName.TARGET, output_field=FieldName.FEAT_TIME, time_features=time_features_from_frequency_str(self.freq), pred_length=self.prediction_length, ), ) dynamic_feat_fields.append(FieldName.FEAT_TIME) if self.add_age_feature: chain.append( AddAgeFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_AGE, pred_length=self.prediction_length, dtype=self.dtype, ), ) dynamic_feat_fields.append(FieldName.FEAT_AGE) if self.use_feat_dynamic_real: dynamic_feat_fields.append(FieldName.FEAT_DYNAMIC_REAL) # we need to make sure that there is always some dynamic input # we will however disregard it in the hybrid forward if len(dynamic_feat_fields) == 0: chain.append( AddConstFeature( target_field=FieldName.TARGET, output_field=FieldName.FEAT_CONST, pred_length=self.prediction_length, dtype=self.dtype, ), ) dynamic_feat_fields.append(FieldName.FEAT_CONST) # now we map all the dynamic input onto FieldName.FEAT_DYNAMIC if len(dynamic_feat_fields) > 1: chain.append( VstackFeatures( output_field=FieldName.FEAT_DYNAMIC, input_fields=dynamic_feat_fields, )) elif len(dynamic_feat_fields) == 1: chain.append( RenameFields({dynamic_feat_fields[0]: FieldName.FEAT_DYNAMIC})) # --- TRANSFORMATION CHAIN FOR STATIC FEATURES --- if not self.use_feat_static_cat: chain.append( SetField( output_field=FieldName.FEAT_STATIC_CAT, value=np.array([0.0]), ), ) # --- SAMPLE AND CUT THE TIME-SERIES --- chain.append( # because of how the forking decoder works, every time step # in context is used for splitting, which is why we use the TestSplitSampler ForkingSequenceSplitter( train_sampler=TestSplitSampler(), enc_len=self.context_length, dec_len=self.prediction_length, encoder_series_fields=[ FieldName.OBSERVED_VALUES, FieldName.FEAT_DYNAMIC, ], decoder_series_fields=[FieldName.OBSERVED_VALUES] + ([FieldName.FEAT_DYNAMIC] if self.enable_decoder_dynamic_feature else []), prediction_time_decoder_exclude=[FieldName.OBSERVED_VALUES], ), ) return Chain(chain)