def profile_method(self, scale=12):

        print('Profile Method')
        orig_train_input = self.ml_obj.training_input
        orig_valid_input = self.ml_obj.validation_input
        train_observations = self.ml_obj.training_target
        valid_observations = self.ml_obj.validation_target

        print(orig_train_input.min(), orig_train_input.max())
        print(orig_valid_input.min(), orig_valid_input.max())

        scale_array = np.linspace(orig_valid_input.min(), orig_valid_input.max(), num=scale)
        fixed_array = np.linspace(orig_valid_input.min(), orig_valid_input.max(), num=10)


        train_predictions = self.ml_obj.best_network[0].sim(orig_train_input)
        valid_predictions = self.ml_obj.best_network[0].sim(orig_valid_input)


        #if self.ml_obj.min_max_scaler_target is not None:
        #    predictions = self.min_max_scaler_target.inverse_transform(predictions)
        #    observations = self.min_max_scaler_target.inverse_transform(observations)

        if True:  # this can be changed to self.min_max_scaler_target is not None (cant yet due to legacy)
            min_max_scaler_target = preprocessing.MinMaxScaler()
            training_target = min_max_scaler_target.fit_transform(self.data_package.training_target)
            train_predictions = min_max_scaler_target.inverse_transform(train_predictions)
            train_observations = min_max_scaler_target.inverse_transform(train_observations)
            valid_predictions = min_max_scaler_target.inverse_transform(valid_predictions)
            valid_observations = min_max_scaler_target.inverse_transform(valid_observations)

        orig_train_rmse = rmse(train_observations, train_predictions, 8)
        orig_valid_rmse = rmse(valid_observations, valid_predictions, 8)

        profile_value_list = []
        for input_num in range(len(orig_train_input[0])):
            input_value_list = []
            for x in scale_array:
                range_value = 0

                for y in fixed_array:
                    input_list = [y] * len(orig_train_input[0])
                    input_list[input_num] = x

                    input_array = np.array(input_list).reshape(1, len(orig_train_input[0]))
                    #print(input_array)

                    train_predictions = self.ml_obj.best_network[0].sim(input_array)
                    train_predictions = min_max_scaler_target.inverse_transform(train_predictions)

                    range_value += train_predictions[0]

                input_value_list.append((range_value[0] / 10.0).__round__(7))

            print(input_value_list)
            profile_value_list.append(input_value_list)
    def perturb_method(self):

        print('Perturb Method')

        orig_train_input = self.ml_obj.training_input
        orig_valid_input = self.ml_obj.validation_input
        train_observations = self.ml_obj.training_target
        valid_observations = self.ml_obj.validation_target

        train_predictions = self.ml_obj.best_network[0].sim(orig_train_input)
        valid_predictions = self.ml_obj.best_network[0].sim(orig_valid_input)


        #if self.ml_obj.min_max_scaler_target is not None:
        #    predictions = self.min_max_scaler_target.inverse_transform(predictions)
        #    observations = self.min_max_scaler_target.inverse_transform(observations)

        if True:  # this can be changed to self.min_max_scaler_target is not None (cant yet due to legacy)
            min_max_scaler_target = preprocessing.MinMaxScaler()
            training_target = min_max_scaler_target.fit_transform(self.data_package.training_target)
            train_predictions = min_max_scaler_target.inverse_transform(train_predictions)
            train_observations = min_max_scaler_target.inverse_transform(train_observations)
            valid_predictions = min_max_scaler_target.inverse_transform(valid_predictions)
            valid_observations = min_max_scaler_target.inverse_transform(valid_observations)

        orig_train_rmse = rmse(train_observations, train_predictions, 8)
        orig_valid_rmse = rmse(valid_observations, valid_predictions, 8)

        for input_num in range(len(orig_train_input[0])):
            input_abs_val = 0
            for x in np.arange(1.1, 1.5, 0.1):
                # Training
                y = orig_train_input.T[input_num] * x
                alt_train_input = np.insert(np.delete(orig_train_input, input_num, 1), input_num, y, 1)

                train_predictions = self.ml_obj.best_network[0].sim(alt_train_input)
                train_predictions = min_max_scaler_target.inverse_transform(train_predictions)
                alt_train_rmse = rmse(train_observations, train_predictions, 8)

                # Validation
                y = orig_valid_input.T[input_num] * x
                alt_valid_input = np.insert(np.delete(orig_valid_input, input_num, 1), input_num, y, 1)

                valid_predictions = self.ml_obj.best_network[0].sim(alt_valid_input)
                valid_predictions = min_max_scaler_target.inverse_transform(valid_predictions)
                alt_valid_rmse = rmse(valid_observations, valid_predictions, 8)

                input_abs_val += abs((orig_train_rmse + orig_valid_rmse) - (alt_train_rmse + alt_valid_rmse))

            #print('input num: {}, input_abs_val: {}'.format(input_num, input_abs_val.__round__(7)))
            print('{}, {}'.format(input_num, input_abs_val.__round__(7)))