classdef (InferiorClasses = {?matlab.graphics.axis.Axes, ?matlab.ui.control.UIAxes}) RegressionGAM ...
        < classreg.learning.regr.FullRegressionModel & ...
        classreg.learning.regr.CompactRegressionGAM
    %RegressionGAM Generalized Additive Model (GAM) for regression.
    %   RegressionGAM is a GAM model for regression. This model can predict
    %   response for new data. This model also stores data used for training
    %   and can compute resubstitution predictions.
    %
    %   Use FITRGAM to create a RegressionGAM object by fitting a GAM model
    %   to training data.
    %
    %   This class is derived from CompactRegressionGAM.
    %
    %   RegressionGAM properties:
    %       NumObservations             - Number of observations.
    %       X                           - Matrix or table of predictors used to train this model.
    %       Y                           - Observed response used to train this model.
    %       W                           - Weights of observations used to train this model.
    %       ModelParameters             - GAM parameters.
    %       PredictorNames              - Names of predictors used for this model.
    %       ExpandedPredictorNames      - Names of expanded predictors.
    %       CategoricalPredictors       - Indices of categorical predictors.
    %       ResponseName                - Name of the response variable.
    %       ResponseTransform           - Transformation applied to predicted regression response.
    %       BinEdges                    - Bin edges for predictors.
    %       Intercept                   - Intercept of the GAM model.
    %       Interactions                - Pairs of predictors used to train the model.
    %       PairDetectionBinEdges       - Bin Edges used for detection of pairs.
    %       ReasonForTermination        - Reason for stopping ensemble training.
    %       RowsUsed                    - Logical index for rows used in fit.
    %       IsStandardDeviationFit      - Flag indicating whether a standard deviation model is fitted.
    %       HyperparameterOptimizationResults - An object or table describing the results of hyperparameter optimization.
    %
    %   RegressionGAM methods:
    %       addInteractions       - Add interactions to univariate GAM.
    %       compact               - Compact this model.
    %       crossval              - Cross-validate this model.
    %       loss                  - Regression loss.
    %       partialDependence     - Partial Dependence values.
    %       plotLocalEffects      - Plot local effects.
    %       plotPartialDependence - Plot Partial Dependence.
    %       predict               - Predicted response of this model.
    %       resubLoss             - Resubstitution regression loss.
    %       resubPredict          - Resubstitution predicted response.
    %       resume                - Resume training of GAM.
    %
    %       Example: Train a GAM regression model
    %       load carsmall
    %       X = [Horsepower,Weight];
    %       Y = MPG;
    %       Mdl = fitrgam(X,Y);
    %
    %   See also fitrgam, classreg.learning.regr.CompactRegressionGAM.
    
    %   Copyright 2020-2023 The MathWorks, Inc.
    
    properties(GetAccess=public,SetAccess=protected,Dependent=true)
        %PairDetectionBinEdges Bin Edges used for detection of predictor pairs.
        %   PairDetectionBinEdges is a cell array with elements equal to the
        %   number of predictors. For categorical predictors, elements of
        %   the cell array are empty.
        %
        %   See also RegressionGAM
        PairDetectionBinEdges;
        
        %ReasonForTermination Reason for stopping GAM training.
        %   ReasonForTermination is a structure containing reason for
        %   termination of training predictor trees and interaction trees.
        %
        %   See also RegressionGAM
        ReasonForTermination;
    end
    
    properties(GetAccess=protected,SetAccess=protected,Hidden=true,Dependent=true)
        %PrivResiduals Residuals from the last iteration of training gam.
        %   PrivResiduals is a vector with elements equal to the
        %   number of observations.
        %
        %   See also RegressionGAM
        PrivResiduals
        
        %PrivTerminationFlag Flag for reason for termination.
        %
        %   See also RegressionGAM
        PrivTerminationFlag
    end
    
    methods
        function a = get.PairDetectionBinEdges(this)
            a = this.Impl.PairDetectionBinEdges;
        end
        function a = get.ReasonForTermination(this)
            a = this.Impl.ReasonForTermination;
        end
        function a = get.PrivResiduals(this)
            a = this.Impl.PrivResiduals;
        end
        function a = get.PrivTerminationFlag(this)
            a = this.Impl.PrivTerminationFlag;
        end
    end
    
    methods(Hidden)
        function this = RegressionGAM(X,Y,W,modelParams,dataSummary,responseTransform)
            if nargin~=6 || ischar(W)
                error(message('stats:RegressionGAM:RegressionGAM:DoNotUseConstructor'))
            end
            this = this@classreg.learning.regr.FullRegressionModel(...
                X,Y,W,modelParams,dataSummary,responseTransform);
            this = this@classreg.learning.regr.CompactRegressionGAM(dataSummary,responseTransform,[]);
            dataSummary.BinnedX = [];
            this = fitGam(this);
        end
    end
    
    methods(Static,Hidden)
        function this = fit(X,Y,varargin)
            temp = RegressionGAM.template(varargin{:});
            this = fit(temp,X,Y);
        end
        
        function temp = template(varargin)
            classreg.learning.FitTemplate.catchType(varargin{:});
            temp = classreg.learning.FitTemplate.make('GAM','type','regression',varargin{:});
        end
        
        function [X,Y,W,dataSummary,responseTransform] = prepareData(X,Y,varargin)
            
            % Separate Interaction Terms from Formula
            [InteractionTerms,Y] = classreg.learning.impl.GAMImpl.separateInteractionTerms(X,Y);
            
            % set default value for NumBins to 256.
            args = {'NumBins'};
            defs  = {256};
            [nbins,~,varargin] = internal.stats.parseArgs(args,defs,varargin{:});
            
            [X,Y,W,dataSummary,responseTransform] = ...
                classreg.learning.regr.FullRegressionModel.prepareData(...
                X,Y,'NumBins',nbins,varargin{:},'OrdinalIsCategorical',false);
            
            % Store Interaction Terms
            dataSummary.InteractionTerms = logical(InteractionTerms);
            
            internal.stats.checkSupportedNumeric('X',X,true);
            internal.stats.checkSupportedNumeric('Weights',W,true);
            if ~dataSummary.ObservationsInRows
                error(message('stats:classreg:learning:FullClassificationRegressionModel:prepareDataCR:ObsInColsNotAllowed','GAM'));
            end
        end
    end
    
    methods(Access = protected)
        function this = fitGam(this)
            doclass = 0; % regression
            
            % nprint based on VerbosityLevel
            if this.ModelParams.VerbosityLevel <= 0
                nprint = 0;
            elseif this.ModelParams.VerbosityLevel == 2
                nprint = 1;
            else
                nprint = this.ModelParams.NumPrint;
            end
            
            this.Impl = classreg.learning.impl.GAMImpl.make(...
                this.PrivX,...
                this.PrivY,...
                this.W * numel(this.PrivY),...
                doclass,...
                this.DataSummary,...
                nprint,...
                this.ModelParams.MaxPValue,...
                this.ModelParams.InitialLearnRateForPredictors,...
                this.ModelParams.InitialLearnRateForInteractions,...
                this.ModelParams.NumTreesPerPredictor,...
                this.ModelParams.NumTreesPerInteraction,...
                this.ModelParams.MaxNumSplitsPerPredictor,...
                this.ModelParams.MaxNumSplitsPerInteraction,...
                this.ModelParams.Interactions,...
                this.ModelParams.VerbosityLevel,...
                this.ModelParams.FitStandardDeviation);
        end
        
        function s = propsForDisp(this,s)
            s = propsForDisp@classreg.learning.regr.CompactRegressionGAM(this,s);
            s = propsForDisp@classreg.learning.regr.FullRegressionModel(this,s);
        end
        
    end
    
    methods
        function cmp = compact(this,varargin)
            %COMPACT Compact GAM model.
            %   CMP = COMPACT(MDL) returns an object of class
            %   CompactRegressionGAM that holds the trained GAM regression
            %   model. The compact object does not contain X and Y used for
            %   training.
            %
            %   See also RegressionGAM,
            %   classreg.learning.regr.CompactRegressionGAM.
            dataSummary = this.DataSummary;
            dataSummary.RowsUsed = [];
            dataSummary.BinnedX = [];
            dataSummary.BinEdges = {};
            
            compactImpl = compact(this.Impl);
            cmp = classreg.learning.regr.CompactRegressionGAM(...
                dataSummary,this.PrivResponseTransform,compactImpl);
        end
        
        function [varargout] = resubPredict(this,varargin)
            %RESUBPREDICT Predict resubstitution response of the FITRGAM.
            %   YFIT = RESUBPREDICT(MDL) returns predicted response YFIT for GAM
            %   regression model MDL and training data MDL.X. YFIT is a vector
            %   of type double with NumObservations elements.
            %
            %   [YFIT,YSD] = RESUBPREDICT(MDL) also returns an N-by-1 vector YSD
            %   such that YSD(i) is the estimated standard deviation of the
            %   response at MDL.X(i,:) from the trained model. This syntax is
            %   valid only when MDL.IsStandardDeviationFit is true. Specify
            %   'FitStandardDeviation' of fitrgam as true to fit the standard
            %   deviation model.
            %
            %   [YFIT,YSD,YINT]= RESUBPREDICT(MDL) also returns an N-by-2 matrix
            %   YINT containing 95% prediction intervals for the responses
            %   corresponding to each row of MDL.X. The lower limits of the bounds
            %   are in YINT(:,1), and the upper limits are in YINT(:,2). This syntax
            %   is valid only when MDL.IsStandardDeviationFit is true. Specify
            %   'FitStandardDeviation' of fitrgam as true to fit the standard
            %   deviation model.
            %
            %   [YFIT,YSD,YINT] = RESUBPREDICT(MDL,'Name1',Value1,'Name2',Value2,...) specifies
            %   optional parameter name/value pairs:
            %       'IncludeInteractions'   - Boolean value to indicate if
            %                                 interactions should be considered
            %                                 when applying the method on a GAM
            %                                 model trained with interactions.
            %                                 Value cannot be true for GAM model
            %                                 trained without interactions.
            %                                 Default: false for MDL without
            %                                 interaction terms and true
            %                                 for MDL with interaction terms.
            %       'Alpha'                   A value between 0 and 1 to specify the
            %                                 confidence level as 100(1-ALPHA)%. Default
            %                                 is 0.05 for 95% confidence.
            %
            %   See also fitrgam, RegressionGAM, predict.
            
            [varargout{1:nargout}] = ...
                resubPredict@classreg.learning.regr.FullRegressionModel(this,varargin{:});
        end
        
        function [varargout] = resubLoss(this,varargin)
            %RESUBLOSS Regression error by resubstitution.
            %   L = RESUBLOSS(MDL) returns the mean squared error for GAM
            %   regression model MDL, computed using the training data MDL.X
            %   and MDL.Y.
            %
            %   L = RESUBLOSS(MDL,'Name1',Value1,'Name2',Value2,...) specifies
            %   optional parameter name/value pairs:
            %       'LossFun'               - Function handle for loss function, or
            %                                 string representing a built-in loss
            %                                 function. Available loss functions for
            %                                 GAM regression: 'mse', and
            %                                 'epsiloninsensitive'. If you pass a
            %                                 function handle FUN, RESUBLOSS calls it as
            %                                 shown below:
            %                                   FUN(Y,Yfit,W)
            %                                   where Y, Yfit and W are numeric
            %                                   vectors of length N. Y is observed
            %                                   response, Yfit is predicted response,
            %                                   and W is observation weights. Default:
            %                                   'mse'
            %       'IncludeInteractions'   - Boolean value to indicate if
            %                                 interactions should be considered
            %                                 when applying the method on a GAM
            %                                 model trained with interactions.
            %                                 Value cannot be true for GAM model
            %                                 trained without interactions.
            %                                 Default: false for MDL without
            %                                 interaction terms and true
            %                                 for MDL with interaction terms.
            %
            %   See also RegressionGAM, loss.
            
            [varargout{1:nargout}] = ...
                resubLoss@classreg.learning.regr.FullRegressionModel(this,varargin{:});
        end
        
        function this = resume(this,numtrees,varargin)
            %RESUME Resume training of GAM.
            %   NEWMDL = RESUME(MDL,NUMTREES) trains model MDL for NUMTREES more iterations.
            %   NUMTREES must be a positive integer scalar.
            %
            %   NEWMDL = RESUME(MDL,NUMTREES,'Name1',Value1,'Name2',Value2,...) specifies optional
            %   parameter name/value pairs:
            %   optional parameter name/value pairs:
            %       'Verbose'       - Verbosity level, one of: 0, 1, or 2. Default:
            %                         Value passed to FITRGAM.
            %       'NumPrint'      - Number of iterations between consecutive
            %                         diagnostic print-outs, a non-negative integer.
            %                         RESUME uses this parameter only if value
            %                         for the 'Verbose' parameter is 1.
            %                         Default: Value passed to FITRGAM.
            %
            % See also RegressionGAM, fitrgam.
            
            [varargin{:}] = convertStringsToChars(varargin{:});
            
            args = {                'NumPrint',                        'Verbose'};
            defs = { this.ModelParams.NumPrint,  this.ModelParams.VerbosityLevel};
            
            [nprint,verbose] = internal.stats.parseArgs(args,defs,varargin{:});
            
            import classreg.learning.modelparams.GAMParams
            
            % Check NumTrees
            isok = GAMParams.isNumericRealScalarNoNaNInf(numtrees,1);
            isok = isok && ~(numtrees<=0) && ~isempty(numtrees);
            if ~isok
                error(message('stats:classreg:learning:impl:GAMImpl:resume:BadNumTrees'))
            else
                numtrees = ceil(numtrees);
            end
            
            if islogical(verbose)
                verbose = double(verbose);
            end
            
            % Check NumPrint and Verbose
            ClassificationGAM.checkNameValuePairs(nprint,verbose,[],[],[],[]);
            
            if verbose <= 0
                nprint = 0;
            elseif verbose == 2
                nprint = 1;
            end
            
            % Update ModelParams
            this.ModelParams.NumPrint       = nprint;
            this.ModelParams.VerbosityLevel = verbose;
            
            % Check model type - set NumTrees* and get MaxNumSplits*
            if isempty(this.TreesPerInteraction)
                this.ModelParams.NumTreesPerPredictor = this.ModelParams.NumTreesPerPredictor + ...
                    numtrees;
                nsplits = this.ModelParams.MaxNumSplitsPerPredictor;
                learnRate = this.ModelParameters.InitialLearnRateForPredictors;
                do1d = true;
            else
                this.ModelParams.NumTreesPerInteraction = this.ModelParams.NumTreesPerInteraction + ...
                    numtrees;
                nsplits = this.ModelParams.MaxNumSplitsPerInteraction;
                learnRate = this.ModelParameters.InitialLearnRateForInteractions;
                do1d = false;
            end
            
            doclass = false; %regression
            
            this.Impl = resume(...
                this.Impl,...
                this.PrivX,...
                this.PrivY,...
                this.W * numel(this.PrivY),...
                doclass,...
                [],... %ClassNames
                learnRate,...
                numtrees,...
                nsplits,...
                verbose,...
                nprint,...
                this.DataSummary,...
                do1d);
        end
        
        function this = addInteractions(this,interactions,varargin)
            %ADDINTERACTIONS Add Interactions to GAM Model.
            %   NEWMDL = ADDINTERACTIONS(MDL,INTERACTIONS) trains model MDL with INTERACTIONS.
            %   INTERACTIONS must be specified as one of:
            %                          * A string:
            %                            - 'all' : P*(P-1)/2 interactions for P predictors.
            %                          * A scalar positive integer: Number of interactions.
            %                          * Logical term matrix specifying interaction pairs.
            %                             A T X P logical matrix with each row identifying
            %                             the pair where P is the number of predictors.
            %
            %   NEWMDL = ADDINTERACTIONS(MDL,INTERACTIONS,'Name1',Value1,'Name2',Value2,...) specifies optional
            %   parameter name/value pairs:
            %       'InitialLearnRateForInteractions' - Learning rate for boosting interaction trees.
            %                        Scalar value between 0 and 1. Default: 1
            %       'MaxPValue'    - Threshold p-value for detection of interaction pairs.
            %                        Scalar value between 0 and 1.
            %                        Default: 1 (all interactions are used)
            %       'MaxNumSplitsPerInteraction' - Maximal Number of splits per interaction
            %                        pair. A positive integer scalar applied to all interactions.
            %                        Default: 4
            %       'NumTreesPerInteraction' - Number of trees trained per interaction pair.
            %                        A positive integer scalar applied to all interactions.
            %                        Default: 100
            %       'Verbose'       - Verbosity level, one of: 0, 1, or 2. Default:
            %                         Value passed to FITRGAM.
            %       'NumPrint'      - Number of iterations between consecutive
            %                         diagnostic print-outs, a non-negative integer.
            %                         ADDINTERACTIONS uses this parameter only if value
            %                         for the 'Verbose' parameter is 1.
            %                         Default: Value passed to FITRGAM.
            %
            % See also RegressionGAM, fitrgam.
            
            [varargin{:}] = convertStringsToChars(varargin{:});
            interactions  = convertStringsToChars(interactions);
            
            % If model is not univariate cannot add interactions
            if ~isempty(this.TreesPerInteraction)
                error(message('stats:RegressionGAM:addInteractions:BadModel'))
            end
            
            % Number of Predictors
            P = size(this.X,2);
            
            % Check interactions
            [isok,interactions] =  ClassificationGAM.checkInteractions(interactions,P);
            
            if ~isok
                error(message('stats:RegressionGAM:addInteractions:BadInteractions'))
            end
            
            % Parse Name-Value Pairs
            args = {'maxpvalue' 'numtreesperinteraction' 'maxnumsplitsperinteraction'...
                'verbose'                'numprint' 'initiallearnrateforinteractions'};
            defs = {          1                      100                            4,...
                this.ModelParams.VerbosityLevel this.ModelParams.NumPrint                                 1};
            
            [maxpval,ntrees,nsplits,verbose,nprint,learnRate] = ...
                internal.stats.parseArgs(args,defs,varargin{:});
            
            if islogical(verbose)
                verbose = double(verbose);
            end
            
            % Validate Name-Value Pairs
            ClassificationGAM.checkNameValuePairs(nprint,verbose,maxpval,ntrees,nsplits,learnRate);
            
            if verbose <= 0
                nprint = 0;
            elseif verbose == 2
                nprint = 1;
            end
            
            % Update ModelParams
            this.ModelParams.NumPrint                        = nprint;
            this.ModelParams.VerbosityLevel                  = verbose;
            this.ModelParams.MaxNumSplitsPerInteraction      = nsplits;
            this.ModelParams.NumTreesPerInteraction          = ntrees;
            this.ModelParams.MaxPValue                       = maxpval;
            this.ModelParams.InitialLearnRateForInteractions = learnRate;
            
            doclass = 0; %Regression
            
            % Call addInteractions from GAMImpl
            this.Impl = addInteractions(...
                this.Impl,...
                this.PrivX,...
                this.PrivY,...
                this.W * numel(this.PrivY),...
                doclass,...
                [],... %ClassNames
                learnRate,...
                ntrees,...
                nsplits,...
                verbose,...
                nprint,...
                this.DataSummary,...
                interactions,...
                maxpval);
        end
        
        function [AX] = plotPartialDependence(this,features,varargin)
            %PLOTPARTIALDEPENDENCE Partial Dependence Plot for 1-D or 2-D visualization
            %   plotPartialDependence(MDL,VAR) creates a plot of the partial
            %   dependence of the response by a fitted regression model MDL on the
            %   predictor VAR. VAR is a scalar containing the index of a predictor or a
            %   character array specifying a predictor name.
            %
            %   plotPartialDependence(...,DATA) specifies the data to be used for
            %   averaging. DATA is a matrix or table of data to be used in place of the
            %   data used in fitting the model.
            %
            %   plotPartialDependence(...,Name,Value) specifies additional options using
            %   one or more name-value pair arguments:
            %
            %   'Conditional'               'none' (default) instructs the method to create
            %                               a partial dependence plot with no conditioning,
            %                               'absolute' to create an individual conditional
            %                               expectation (ICE) plot, and 'centered' to
            %                               create an ICE plot with centered data.
            %
            %   'NumObservationsToSample'   An integer specifying the number
            %                               of rows to sample at random from the dataset
            %                               (either the data specified by the argument DATA
            %                               or the data used to train MDL). The default
            %                               is to use all rows.
            %
            %   'QueryPoints'               The points at which to calculate
            %                               the partial dependence. For the case of a
            %                               single predictor, the value of 'QueryPoints'
            %                               must be a column vector. For the case of two
            %                               predictors, the value of 'QueryPoints' must be
            %                               a 1x2 cell array containing a separate vector
            %                               for each predictor. The default is to use 100
            %                               points equally spaced across the range of the
            %                               predictor.
            %
            %   'UseParallel'               Can be true to instruct the method to perform
            %                               the averaging calculations in parallel (using
            %                               parfor), or false (default) to instruct the
            %                               method not to use parallel computations.
            %
            % 	'Parent'                    Instructs the method to create a partial
            %                               dependence plot using the axes with handle
            %                               specified by the value of this parameter.
            %
            %   'IncludeIntercept'          Can be true to include the intercept value in
            %                               the partial dependence computation,
            %                               or false to not use the intercept
            %                               term. Default: true.
            %
            %   'IncludeInteractions'       Can be true to include the interactions in the
            %                               partial dependence computation for a GAM
            %                               model trained with interactions, or false to exclude
            %                               interaction terms from the computation of
            %                               partial dependence.
            %                               Default: false for MDL without
            %                               interaction terms and true
            %                               for MDL with interaction terms.
            %
            %   AX = plotPartialDependence(...) returns a handle AX to the axes of the
            %   plot.
            %
            %   Examples:
            %      % Partial Dependence Plot of Regression GAM
            %      load carsmall
            %      tbl = table(Weight,Cylinders,Origin,MPG);
            %      f = fitrgam(tbl,'MPG');
            %
            %      plotPartialDependence(f,'Weight');
            %      plotPartialDependence(f,{'Weight','Origin'});
            %      plotPartialDependence(f,[1,3]);
            %
            %      % Obtain optional output Axes handle
            %      ax = plotPartialDependence(f,1);
            %
            %      % With additional Data
            %      load carbig
            %      tbl2 = table(Weight,Cylinders,Origin);
            %      plotPartialDependence(f,'Weight',tbl2);
            %      plotPartialDependence(f,1,tbl2);
            %
            %      % With optional name-value pairs
            %      plotPartialDependence(f,1,tbl2,'NumObservationsToSample',100);
            %      plotPartialDependence(f,1,tbl2,'UseParallel',true);
            %      plotPartialDependence(f,1,tbl2,'UseParallel',true,'Conditional','none');
            %
            %      % Plot the Individual Conditional Expectation
            %      plotPartialDependence(f,1,tbl2,'Conditional','absolute');
            %
            %      % Provide alternative query points
            %      xi = linspace(min(Weight),max(Weight))';
            %      plotPartialDependence(f,1,'QueryPoints',xi);
            %
            %      xi = cell(1,2);
            %      xi{1} = linspace(min(Weight),max(Weight))';
            %      xi{2} = linspace(min(Cylinders),max(Cylinders))';
            %      plotPartialDependence(f,[1,2],'QueryPoints',xi);
            %
            % See also RegressionGAM, fitrgam.
            
            features = convertStringsToChars(features);
            [varargin{:}] = convertStringsToChars(varargin{:});
            
            % Default values for include interactions
            if isempty(this.TreesPerInteraction)
                defaultui = false;
            else
                defaultui = true;
            end
            
            % Check inputs with inputParser. This step ensures that the third
            % argument is either a Name-Value pair or data, no other strings/char
            % array allowed.
            p = inputParser;
            addRequired(p,'Model');
            addRequired(p,'Var');
            addOptional(p,'Data',this.X); % Default - training data
            addParameter(p,'Conditional',{'none','absolute','centered'});
            addParameter(p,'NumObservationsToSample',0);
            addParameter(p,'QueryPoints',[]);
            addParameter(p,'UseParallel',false);
            addParameter(p,'ParentAxisHandle',[]);
            addParameter(p,'IncludeInteractions',defaultui);
            addParameter(p,'IncludeIntercept',true);
            % Allowing additional Name-Value pairs specific to custom models
            % here so that a more specific error message can be thrown when parsing.
            addParameter(p,'CategoricalPredictors',[]);
            addParameter(p,'OutputColumns',[]);

            parse(p,this,features,varargin{:});
            X = p.Results.Data;
            incinteractions = p.Results.IncludeInteractions;
            incintercept = p.Results.IncludeIntercept;
            
            %------Parse Data-----------------
            % If third argument is a char, its a parameter name else it is Data
            if(nargin>2 && ~ischar(varargin{1}))
                % Pass everything but the first argument(Data)to compact method
                varargin = varargin(2:end);
            end
            
            % Validate GAM Name Value Pairs
            internal.stats.parseOnOff(incinteractions,'IncludeInteractions');
            internal.stats.parseOnOff(incintercept,'IncludeIntercept');
            
            if ((incinteractions) && isempty(this.TreesPerInteraction))
                error(message('stats:classreg:learning:impl:CompactGAMImpl:parseIncludeArgs:BadIncludeInteractions'))
            end
            
            % Since this is a regression model, the classification flag is false
            % and class label is empty
            classif = false;
            label = [];
            
            % Call the function from responsible.impl
            ax = responsible.impl.plotPartialDependence(this,features,...
                label,X,classif,varargin{:});
            if(nargout > 0)
                AX = ax;
            end
        end
        
        function [pd,varargout] = partialDependence(this,features,varargin)
            %PARTIALDEPENDENCE Partial Dependence for one and two variables
            %   PD = partialDependence(MDL,VAR) returns a vector PD of partial
            %   dependence for a single predictor variable VAR, and input data DATA,
            %   based on the response of a fitted regression model MDL. VAR is a
            %   scalar containing the index of a predictor or a character array
            %   specifying a predictor name.
            %
            %   PD = partialDependence(MDL,VARS) returns a two dimensional
            %   array PD of the partial dependences for two predictors VARS, based on
            %   the response of a fitted regression model MDL. VARS is either a cell
            %   array containing two predictor names, or a two-element vector containing
            %   the indices of two predictors.
            %
            %   PD = partialDependence(...,DATA) specifies the data to be used for
            %   averaging. DATA is a matrix or table of data to be used in place of the
            %   data used in fitting the model.
            %
            %   PD = partialDependence(...,Name,Value) specifies additional options
            %   using one or more name-value pair arguments:
            %
            %       'NumObservationsToSample':      An integer specifying the number
            %                                       of rows to sample at random from the
            %                                       dataset (either the data specified by
            %                                       argument DATA or the data used to train
            %                                       MDL). The default is to use all rows.
            %
            %       'QueryPoints':                  The points at which to calculate
            %                                       the partial dependence. For the case of
            %                                       a single predictor, the value of
            %                                       'QueryPoints' must be a column vector.
            %                                       For the case of two predictors, the
            %                                       value of 'QueryPoints' must be a 1x2
            %                                       cell array containing a separate vector
            %                                       for each predictor. The default is to
            %                                       use 100 points equally spaced across
            %                                       the range of the predictor.
            %
            %       'UseParallel'                   Can be true to instruct the method to
            %                                       perform the averaging calculations in
            %                                       parallel (using parfor), or false
            %                                       (default) to instruct the method not to
            %                                       use parallel computation.
            %
            %       'IncludeIntercept'              Can be true to include the intercept value in
            %                                       the partial dependence computation,
            %                                       or false to not use the intercept
            %                                       term. Default: true.
            %
            %       'IncludeInteractions'           Can be true to include the interactions in the
            %                                       partial dependence computation for a GAM
            %                                       model trained with interactions, or false to exclude
            %                                       interaction terms from the computation of
            %                                       partial dependence.
            %                                       Default: false for MDL without
            %                                       interaction terms and true
            %                                       for MDL with interaction terms.
            %
            %   [PD,X,Y] = partialDependence(...) also returns the arrays X and Y
            %   containing the query point values of the first and second predictor in VARS,
            %   respectively.
            %
            %   Examples:
            %       % Partial Dependence Plot of Regression GAM
            %       load carsmall
            %       tbl = table(Weight,Cylinders,Origin,MPG);
            %       f = fitrgam(tbl,'MPG');
            %
            %       pd = partialDependence(f,'Weight');
            %       pd = partialDependence(f,{'Weight','Origin'});
            %
            %
            %       % Obtain optional output Axes handle
            %       [pd,x] = partialDependence(f,1);
            %       plot(x,pd)
            %
            %       % Obtain values x and y of the first and second variables
            %       [pd,x,y] = partialDependence(f,[1,3]);
            %       surf(x,y,pd)
            %
            %       % With additional Data
            %       load carbig
            %       tbl2 = table(Weight,Cylinders,Origin);
            %       pd = partialDependence(f,'Weight',tbl2);
            %       pd = partialDependence(f,1,tbl2);
            %
            %       % With optional name-value pairs
            %       pd = partialDependence(f,1,tbl2,'NumObservationsToSample',100);
            %       pd = partialDependence(f,1,tbl2,'UseParallel',true);
            %
            %       % Provide alternative query points
            %       xi = linspace(min(Weight),max(Weight))';
            %       pd = partialDependence(f,1,'QueryPoints',xi);
            %
            %       xi = cell(1,2);
            %       xi{1} = linspace(min(Weight),max(Weight))';
            %       xi{2} = linspace(min(Cylinders),max(Cylinders))';
            %       pd = partialDependence(f,[1,2],'QueryPoints',xi);
            %
            % See also RegressionGAM, fitrgam.
            
            features = convertStringsToChars(features);
            [varargin{:}] = convertStringsToChars(varargin{:});
            
            % Default values for include interactions
            if isempty(this.TreesPerInteraction)
                defaultui = false;
            else
                defaultui = true;
            end
            
            % Check inputs with inputParser. This step ensures that the third
            % argument is either a Name-Value pair or data, no other strings/char
            % array allowed.
            p = inputParser;
            addRequired(p,'Model');
            addRequired(p,'Var');
            addOptional(p,'Data',this.X); % Default - training data
            addParameter(p,'NumObservationsToSample',0);
            addParameter(p,'QueryPoints',[]);
            addParameter(p,'UseParallel',false);
            addParameter(p,'IncludeInteractions',defaultui);
            addParameter(p,'IncludeIntercept',true);
            % Allowing additional Name-Value pairs specific to custom models
            % here so that a more specific error message can be thrown when parsing.
            addParameter(p,'CategoricalPredictors',[]);
            addParameter(p,'OutputColumns',[]);

            parse(p,this,features,varargin{:});
            X = p.Results.Data;
            incinteractions = p.Results.IncludeInteractions;
            incintercept = p.Results.IncludeIntercept;
            
            % Since this is a regression model, the classification flag is false
            % and class label is empty
            classif = false;
            label = [];
            
            %------Parse Data-----------------
            % If third argument is a char, its a parameter name else it is Data
            if(nargin>2 && ~ischar(varargin{1}))
                % Pass everything but the first argument (Data) to compact method
                varargin = varargin(2:end);
            end
            
            % Validate GAM Name Value Pairs
            internal.stats.parseOnOff(incinteractions,'IncludeInteractions');
            internal.stats.parseOnOff(incintercept,'IncludeIntercept');
            
            if ((incinteractions) && isempty(this.TreesPerInteraction))
                error(message('stats:classreg:learning:impl:CompactGAMImpl:parseIncludeArgs:BadIncludeInteractions'))
            end
            
            % Call the function from responsible.impl
            [pd,x,y] = responsible.impl.partialDependence(this,features,...
                label,X,classif,varargin{:});
            varargout{1} = x;
            varargout{2} = y;
        end
        
        function partModel = crossval(this,varargin)
            %CROSSVAL Cross-validate this model.
            %   CVMODEL = CROSSVAL(MDL) builds a partitioned model CVMODEL from model
            %   MDL represented by a full object for regression. You can then
            %   assess the predictive performance of this model on cross-validated data
            %   using methods and properties of CVMODEL. By default, CVMODEL is built
            %   using 10-fold cross-validation on the training data.
            %
            %   CVMODEL = CROSSVAL(MDL,'PARAM1','Name1',Value1,'Name2',Value2,...) specifies
            %   optional parameter name/value pairs:
            %      'KFold'      - Number of folds for cross-validation, a numeric
            %                     positive scalar; 10 by default.
            %      'Holdout'    - Holdout validation uses the specified
            %                     fraction of the data for test, and uses the rest of
            %                     the data for training. Specify a numeric scalar
            %                     between 0 and 1.
            %      'Leaveout'   - If 'on', use leave-one-out cross-validation.
            %      'CVPartition' - An object of class CVPARTITION; empty by default. If
            %                      a CVPARTITION object is supplied, it is used for
            %                      splitting the data into subsets.
            %
            %   See also fitrgam, RegressionGAM, cvpartition,
            %   classreg.learning.partition.RegressionPartitionedGAM.
            
            % Set verbosity to 0 for cross validation.
            this.ModelParams.VerbosityLevel = 0;
            
            % Call superclass method.
            partModel = crossval@classreg.learning.regr.FullRegressionModel(this,varargin{:});
            
        end % end of crossval.
    end
end
