def model(self, data,
            ind_col=None, dep_col=None,
            project_ind_col=None,
            baseline_period=[None, None], projection_period=None, exclude_time_period=None,
            alphas=np.logspace(-4,1,30),
            cv=3, plot=True, figsize=None,
            custom_model_func=None):
        """ Split data into baseline and projection periods, run models on them and display metrics & plots.

        Parameters
        ----------
        data                    : pd.DataFrame()
            Dataframe to model.
        ind_col                 : list(str)
            Independent column(s) of dataframe. Defaults to all columns except the last.
        dep_col                 : str
            Dependent column of dataframe.
        project_ind_col         : list(str)
            Independent column(s) to use for projection. If none, use ind_col.
        baseline_period         : list(str)
            List of time periods to split the data into baseline periods. It needs to have a start and an end date.
        projection_period       : list(str)
            List of time periods to split the data into projection periods. It needs to have a start and an end date.
        exclude_time_period     : list(str)
            List of time periods to exclude for modeling.
        alphas                  : list(int)
            List of alphas to run regression on.
        cv                      : int
            Number of folds for cross-validation.
        plot                    : bool
            Specifies whether to save plots or not.
        figsize                 : tuple
            Size of the plots.
        custom_model_func       : function
            Model with specific hyper-parameters provided by user.

        Returns
        -------
        dict
            Metrics of the optimal/best model.

        """

        # Check to ensure data is a pandas dataframe
        if not isinstance(data, pd.DataFrame):
            raise SystemError('data has to be a pandas dataframe.')
        
        # Create instance
        model_data_obj = Model_Data(data, ind_col, dep_col, alphas, cv, exclude_time_period, baseline_period, projection_period)

        # Split data into baseline and projection
        model_data_obj.split_data()

        # Logging
        self.result['Model'] = {
            'Independent Col': ind_col,
            'Dependent Col': dep_col,
            'Projection Independent Col': project_ind_col,
            'Baseline Period': baseline_period,
            'Projection Period': projection_period,
            'Exclude Time Period': exclude_time_period,
            'Alphas': list(alphas),
            'CV': cv,
            'Plot': plot,
            'Fig Size': figsize
        }

        # Runs all models on the data and returns optimal model
        all_metrics = model_data_obj.run_models()
        self.result['Model']['All Model\'s Metrics'] = all_metrics

        # CHECK: Define custom model's parameter and return types in documentation.
        if custom_model_func:
            self.result['Model']['Custom Model\'s Metrics'] = model_data_obj.custom_model(custom_model_func)

        # Fit optimal model to data
        self.result['Model']['Optimal Model\'s Metrics'] = model_data_obj.best_model_fit()

        if plot:

            # Use project_ind_col if projecting into the future (no input data other than weather data)
            input_col = model_data_obj.input_col if not project_ind_col else project_ind_col
            fig, y_true, y_pred = self.plot_data_obj.baseline_projection_plot(model_data_obj.y_true, model_data_obj.y_pred, 
                                                            model_data_obj.baseline_period, model_data_obj.projection_period,
                                                            model_data_obj.best_model_name, model_data_obj.best_metrics['adj_r2'],
                                                            model_data_obj.original_data,
                                                            input_col, model_data_obj.output_col,
                                                            model_data_obj.best_model,
                                                            self.result['Site'])

            fig.savefig(self.results_folder_name + '/baseline_projection_plot-' + str(self.get_global_count()) + '.png')
            
            if not y_true.empty and not y_pred.empty:
                saving_absolute = (y_pred - y_true).sum()
                saving_perc = (saving_absolute / y_pred.sum()) * 100
                self.result['Energy Savings (%)'] = float(saving_perc)
                self.result['Energy Savings (absolute)'] = saving_absolute

                # Temporary
                self.project_df['true'] = y_true
                self.project_df['pred'] = y_pred

                # Calculate uncertainity of savings
                self.result['Uncertainity'] = self.uncertainity_equation(model_data_obj, y_true, y_pred, 0.9)
            
            else:
                print('y_true: ', y_true)
                print('y_pred: ', y_pred)
                print('Error: y_true and y_pred are empty. Default to -1.0 savings.')
                self.result['Energy Savings (%)'] = float(-1.0)
                self.result['Energy Savings (absolute)'] = float(-1.0)
        
        return self.best_metrics
Split data into baseline and projection periods, run models on them and display metrics & plots.

        Parameters
        ----------
        data                    : pd.DataFrame()
            Dataframe to model.
        ind_col                 : list(str)
            Independent column(s) of dataframe. Defaults to all columns except the last.
        dep_col                 : str
            Dependent column of dataframe.
        project_ind_col         : list(str)
            Independent column(s) to use for projection. If none, use ind_col.
        baseline_period         : list(str)
            List of time periods to split the data into baseline periods. It needs to have a start and an end date.
        projection_period       : list(str)
            List of time periods to split the data into projection periods. It needs to have a start and an end date.
        exclude_time_period     : list(str)
            List of time periods to exclude for modeling.
        alphas                  : list(int)
            List of alphas to run regression on.
        cv                      : int
            Number of folds for cross-validation.
        plot                    : bool
            Specifies whether to save plots or not.
        figsize                 : tuple
            Size of the plots.
        custom_model_func       : function
            Model with specific hyper-parameters provided by user.

        Returns
        -------
        dict
            Metrics of the optimal/best model.