%% Impute Missing Data in the Credit Scorecard Workflow Using the Random Forest Algorithm
% This example shows how to perform imputation of missing data in the credit scorecard workflow using the random forest algorithm.
% Random forests are an ensemble learning method for classification or regression that operates by constructing a multitude of decision trees at training time and obtaining the class that is the mode of the classes (classification) or mean prediction (regression) of the individual trees. Random forests correct for the tendency of decision trees to overfit to the training set. For more information on the random forest algorithm, see fitrensemble and fitcensemble.
% For additional information on alternative approaches for "treating" missing data, see Credit Scorecard Modeling with Missing Values.
%
%% Impute Missing Data Using Random Forest Algorithm
% Use the dataMissing data set to impute missing values for the CustAge (numeric) and ResStatus (categorical) predictors.

load CreditCardData.mat
disp(head(dataMissing));

% Remove the 'CustID' and 'status' columns in the imputation process as these are the id and response values respectively. Alternatively, you can choose to leave the 'status' column in.

dataToImpute = dataMissing(:,setdiff(dataMissing.Properties.VariableNames,...
    {'CustID','status'},'stable'));

rfImputedData = dataMissing;

% Because multiple predictors contain missing data, turn on the 'Surrogate' flag when you create the decision tree template.

rng('default');
tmp = templateTree('Surrogate','on','Reproducible',true);

% Next, use the fitrensemble and fitcensemble functions, which return the trained regression and classification ensemble model objects contain the results of boosting 100 regression and classification trees using LSBoost, respectively.

missingCustAge = ismissing(dataToImpute.CustAge);
% Fit ensemble of regression learners
rfCustAge = fitrensemble(dataToImpute,'CustAge','Method','Bag',...
    'NumLearningCycles',200,'Learners',tmp,'CategoricalPredictors',...
    {'ResStatus','EmpStatus','OtherCC'});
rfImputedData.CustAge(missingCustAge) = predict(rfCustAge,...
    dataToImpute(missingCustAge,:));

missingResStatus = ismissing(dataToImpute.ResStatus);
% Fit ensemble of classification learners
rfResStatus = fitcensemble(dataToImpute,'ResStatus','Method','Bag',...
    'NumLearningCycles',200,'Learners',tmp,'CategoricalPredictors',...
    {'EmpStatus','OtherCC'});
rfImputedData.ResStatus(missingResStatus) = predict(rfResStatus,...
    dataToImpute(missingResStatus,:));

% Optionally, round the age to the nearest integer
rfImputedData.CustAge = round(rfImputedData.CustAge);

%
%% Compare Imputed Data to Original Data

disp(rfImputedData(5:10,:));
disp(rfImputedData(find(missingCustAge,5),:));
disp(rfImputedData(find(missingResStatus,5),:));

%
% Plot a histogram of the predictor values before and after imputation.
%

Predictor = "CustAge";
f1 = figure;
ax1 = axes(f1);
histogram(ax1,rfImputedData.(Predictor),'FaceColor','red','FaceAlpha',1);
hold on
histogram(ax1,dataMissing.(Predictor),'FaceColor','blue','FaceAlpha',1);
legend(strcat("Imputed ", Predictor), strcat("Observed ", Predictor));
title(strcat("Histogram of ", Predictor));

%
%% Create Credit Scorecard Model Using New Imputed Data
% Use the imputed data to create the creditscorecard object, and then use autobinning, fitmodel, and formatpoints to create a credit scorecard model.

sc = creditscorecard(rfImputedData,'IDVar','CustID');
sc = autobinning(sc);
[sc,mdl] = fitmodel(sc,'display','off');
sc = formatpoints(sc,'PointsOddsAndPDO',[500 2 50]);
PointsInfo = displaypoints(sc);
disp(PointsInfo);

%
%% Calculate Scores and Probability of Default for New Customers
% Create a data set of 'new customers' and then calculate the scores and probabilities of default.

dataNewCustomers = dataMissing(1:20,1:end-1);
disp(head(dataNewCustomers));

% Predict missing data in the scoring data set with the same imputation model as before.

missingCustAgeNewCustomers = isnan(dataNewCustomers.CustAge);
missingResStatusNewCustomers = ismissing(dataNewCustomers.ResStatus);
imputedCustAgeNewCustomers = round(predict(rfCustAge, dataNewCustomers(missingCustAgeNewCustomers,:)));
imputedResStatusNewCustomers = predict(rfResStatus, dataNewCustomers(missingResStatusNewCustomers,:));
dataNewCustomers.CustAge(missingCustAgeNewCustomers) = imputedCustAgeNewCustomers;
dataNewCustomers.ResStatus(missingResStatusNewCustomers) = imputedResStatusNewCustomers;

% Use score to calculate the scores of the new customers.

[scores, points] = score(sc, dataNewCustomers);
disp(scores);
disp(points);

% Copyright 2019 The MathWorks, Inc.