function Perform_CTREE(NumTopics,Basis,YearRange)
 
% ----- NAME -----
%
% Perform_CTREE
%
% Updated 26 June 2017 by Michael Bode and Katherine Bode.
% Email: katherine.bode@anu.edu.au
%
% ----- DESCRIPTION -----
%
% Classifies ....
%
% ----- INPUTS -----
%
% NumTopics
%    The number of ... this identifies the input XLS spreadsheet analysed ...
%
%    Example: 100 (for 100 topics OCR removed.xls)
%
% Basis
%    Indicates what the classification tree is trying to predict about a title
%
%    Options: 'N'    - Identify the nationality of the author
%             'L'    - Identify the location of the published work
%             'G'    - Identify the gender of the author
%
% YearRange
%    Indicates
%
%    Example: [1890 1889]
%
% ----- OUTPUTS -----
%
% No outputs.
%

[D,T] = xlsread([num2str(NumTopics) ' topics ocr removed.xlsx']); % not sure what D,T means?
 
% Identifies references in spreadsheet
TopicName = T(1,14:end);
Author = T(2:end,2);
Gender = T(2:end,3);
Nationality = T(2:end,4);
Titles = T(2:end,7);
Dates = D(1:end,8);
Location = T(2:end,13);
save ExcelData
 
clear all
load ExcelData D Gender Nationality Location Titles Author TopicName Basis Dates NumTopics YearRange
 
% Remove titles with particular characteristics (e.g., unknown genders, multiple nationalities).
FF = [find(isnan(D(:,5))); ...
   find(strcmp(Gender,'Unknown')); ...
   find(strcmp(Gender,'Both')); ...
   find(strcmp(Nationality,'Multiple')); ...
   find(strcmp(Nationality,'Other')); ...
   find(strcmp(Location,'Suburban')); ...
   find(Dates < YearRange(1) | Dates > YearRange(2))];
D(FF,:) = []; Gender(FF) = []; Nationality(FF) = []; Location(FF) = []; Titles(FF) = []; Dates(FF) = []; Author(FF) = [];
 
% This classification method is tested using straight (e.g., 1-fold) cross-validation.
% This variable determines the size of the training data set.
SizeTrainingSet = 0.8; 
 
% Classification trees have a pre-specified complexity, determined by the minimum number of
% splits. This variable sets that value.
MNS = 2;
 
% Standardise variations (e.g., spelling, whitespace) in the metadata
for i = 1:length(Nationality) 
   if strcmp(Nationality(i),'American ') == 1; Nationality{i} = 'American'; end
   if strcmp(Nationality(i),'Australian ') == 1; Nationality{i} = 'Australian'; end
   if strcmp(Nationality(i),'British ') == 1; Nationality{i} = 'British'; end
   if strcmp(Nationality(i),'Australian/New Zealand') == 1; Nationality{i} = 'Aust-NZ'; end
   if strcmp(Gender(i),'male') == 1; Gender{i} = 'Male'; end
   if strcmp(Nationality(i),'American') == 1; Nationality{i} = 'USA'; end
   if strcmp(Nationality(i),'New Zealand') == 1; Nationality{i} = 'NZ'; end
   if strcmp(Nationality(i),'South African') == 1; Nationality{i} = 'RZA'; end
   if strcmp(Nationality(i),'Aust-NZ') == 1; Nationality{i} = 'Australian'; end
   
   if strcmp(Nationality(i),'NZ') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'Canadian') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'RZA') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'Irish') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'Russian') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'Austrian') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'French') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'German') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'Dutch') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'Swedish') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'Australian/New Zealand') == 1; Nationality{i} = 'Other'; end
   if strcmp(Nationality(i),'Unknown') == 1; Nationality{i} = 'Other'; end
   
   Gender_Nat{i} = [Gender{i} '/' Nationality{i}];
end
Themes = D(:,14:end);
 
% Identify unique nationalities, genders and locations
UGN = unique(Gender_Nat);
UN = unique(Nationality);
UL = {'Metropolitan';'Provincial';'Both'};
 
% Create names for the output files
NumThemes = size(Themes,2);
for i = 1:NumThemes
   TopicName{i} = ['T-' TopicName{i}];
end
disp('In confusion matrices, rows indicate predictions, columns indicate truths')
 
if Basis == 'N'   
   %% === Predict Nationality === 
   NumTitles = size(Themes,1);
   
   % Create balanced training set for cross-validation
   AllALoc = find(strcmp(Nationality,'Australian'));
   AllBLoc = find(strcmp(Nationality,'British'));
   AllULoc = find(strcmp(Nationality,'USA'));
   EachTrainingSetSize = ceil(SizeTrainingSet*min([length(AllALoc),length(AllBLoc),length(AllULoc)]));
   TrainingSet = [randsample(AllALoc,EachTrainingSetSize);randsample(AllBLoc,EachTrainingSetSize) ...
      ;randsample(AllULoc,EachTrainingSetSize)];
   ValidateSet = [randsample(AllALoc,EachTrainingSetSize);randsample(AllBLoc,EachTrainingSetSize) ...
      ;randsample(AllULoc,EachTrainingSetSize)];
   disp(['Training on ' num2str(length(TrainingSet))])
   disp(['Validating on ' num2str(length(ValidateSet))])
   RandomSet = randsample(NumTitles,length(ValidateSet));
   
   % Train the Matlab function 'ctree' on the data in the training set
   ctree = fitctree(Themes(TrainingSet,:),Nationality(TrainingSet),'MaxNumSplits',MNS,'PredictorNames',TopicName);
   
   % Use the trained classification tree to predict the characteristics of the validation set
   Predict_Nat = predict(ctree,Themes(ValidateSet,:));
   
   % What is the true nationality of the titles in the validation set?
   Truth_Nat = Nationality(ValidateSet);
   
   % Construct a random analogue to the validation set, 
   % to see whether the classification tree performs significantly better than random chance
   Random_Nat = Nationality(RandomSet);
   
   % This section of code calculates the confusion matrix for both the classified and random datasets
   True = 0; RandomTrue = 0; Conf = zeros(length(UN)); Misallocate = [];
   for v = 1:length(Predict_Nat)
      if strcmp(Predict_Nat{v},Truth_Nat{v})==1
         True = True + 1;
         Misallocate = [Misallocate; [Titles((ValidateSet(v))) Truth_Nat{v} Predict_Nat{v} Gender((ValidateSet(v))) Location((ValidateSet(v))) Nationality((ValidateSet(v))) Author((ValidateSet(v)))]];
      end
      if strcmp(Random_Nat{v},Truth_Nat{v})==1
         RandomTrue = RandomTrue + 1;
      end
      for a = 1:length(UN)
         for b = 1:length(UN)
            if strcmp(Predict_Nat{v},UN{a})==1 & strcmp(Truth_Nat{v},UN{b})==1; Conf(a,b) = Conf(a,b) + 1; end
         end
      end
   end
   
   % Display outputs of the process
   disp('== Nationality ==')
   Accuracy = True/length(Predict_Nat)
   ExpectedAccuracy = RandomTrue/length(Predict_Nat)
   ctree2 = ctree;
   
   % Display the classification tree visually
   view(ctree,'mode','graph');
   
   % Calculate and display the confusion matrix
   Conf = Conf./repmat(sum(Conf,1),size(Conf,1),1);
   Conf(isnan(Conf))=0
   UN
   
   % Output the results to a CSV file
   Misallocate = [[{'Title','True nationality','Misallocated nationality','G','L','N','A'}]; Misallocate];
   cell2csv(['Misallocated_Nationalities_Splits_' num2str(MNS) '_Topics_' num2str(NumTopics) '_Years_'  num2str(YearRange(1)) '_' num2str(YearRange(2)) '.csv'],Misallocate,'_')
elseif Basis == 'L'
   
   %% === Predict Location ===
   NumTitles = size(Themes,1);
   
   % Create balanced training set for cross-validation
   AllALoc = find(strcmp(Location,'Metropolitan'));
   AllBLoc = find(strcmp(Location,'Provincial'));
   EachTrainingSetSize = ceil(SizeTrainingSet*min([length(AllALoc),length(AllBLoc)]));
   TrainingSet = [randsample(AllALoc,EachTrainingSetSize);randsample(AllBLoc,EachTrainingSetSize)];
   ValidateSet = [randsample(AllALoc,EachTrainingSetSize);randsample(AllBLoc,EachTrainingSetSize)];
   disp(['Training on ' num2str(length(TrainingSet))])
   disp(['Validating on ' num2str(length(ValidateSet))])
   RandomSet = randsample(NumTitles,length(ValidateSet));
   
   % Train the Matlab function 'ctree' on the data in the training set
   ctree = fitctree(Themes(TrainingSet,:),Location(TrainingSet),'MaxNumSplits',MNS,'PredictorNames',TopicName);
   
   % Use the trained classification tree to predict the characteristics of the validation set
   Predict_Loc = predict(ctree,Themes(ValidateSet,:));
   
   % What is the true location of the titles in the validation set?
   Truth_Loc = Location(ValidateSet);
   
   % Construct a random analogue to the validation set, 
   % to see whether the classification tree performs significantly better than random chance
   Random_Loc = Location(RandomSet);
   
   % This section of code calculates the confusion matrix for both the classified and random datasets
   True = 0; RandomTrue = 0; Conf = zeros(length(UL)); Misallocate = [];
   for v = 1:length(Predict_Loc)
      if strcmp(Predict_Loc{v},Truth_Loc{v})==1
         True = True + 1;
      else
         Misallocate = [Misallocate; [Titles((ValidateSet(v))) Truth_Loc{v} Predict_Loc{v} Gender((ValidateSet(v))) Location((ValidateSet(v))) Nationality((ValidateSet(v))) Author((ValidateSet(v)))]];
      end
      if strcmp(Random_Loc{v},Truth_Loc{v})==1
         RandomTrue = RandomTrue + 1;
      end
      for a = 1:length(UL)
         for b = 1:length(UL)
            if strcmp(Predict_Loc{v},UL{a})==1 & strcmp(Truth_Loc{v},UL{b})==1;
               Conf(a,b) = Conf(a,b) + 1;
            end
         end
      end
   end
   
   % Display outputs of the process
   disp('== Location ==')
   Accuracy = True/length(Predict_Loc)
   ExpectedAccuracy = RandomTrue/length(Predict_Loc)
   ctree2 = ctree;
   
   % Display the classification tree visually
   view(ctree,'mode','graph');
   
   % Calculate and display the confusion matrix
   Conf = Conf./repmat(sum(Conf,1),size(Conf,1),1);
   Conf(isnan(Conf))=0
   UL
   
   % Output the results to a CSV file
   Misallocate = [[{'Title','True location','Misallocated location','G','L','N','A'}]; Misallocate];
   cell2csv(['Misallocated_Locations_Splits_' num2str(MNS) '_Topics_' num2str(NumTopics) '_Years_'  num2str(YearRange(1)) '_' num2str(YearRange(2)) '.csv'],Misallocate,'_')
   
elseif Basis == 'G'
   
   %% === Predict gender ===
   NumTitles = size(Themes,1);
   
   % Create balanced training set for cross-validation
   AllMalesLoc = find(strcmp(Gender,'Male'));
   AllFemalesLoc = find(strcmp(Gender,'Female'));
   EachTrainingSetSize = ceil(SizeTrainingSet*min(length(AllMalesLoc),length(AllFemalesLoc)));
   TrainingSet = [randsample(AllMalesLoc,EachTrainingSetSize);randsample(AllFemalesLoc,EachTrainingSetSize)];
   ValidateSet = [randsample(AllMalesLoc,EachTrainingSetSize);randsample(AllFemalesLoc,EachTrainingSetSize)];
   disp(['Training on ' num2str(length(TrainingSet))])
   disp(['Validating on ' num2str(length(ValidateSet))])
   RandomSet = randsample(NumTitles,length(ValidateSet));
   
   % Train the Matlab function 'ctree' on the data in the training set
   ctree = fitctree(Themes(TrainingSet,:),Gender(TrainingSet),'MaxNumSplits',MNS,'PredictorNames',TopicName);
   
   % Use the trained classification tree to predict the characteristics of the validation set
   Predict_Gender = predict(ctree,Themes(ValidateSet,:));
   
   % What is the true gender for the titles in the validation set?
   Truth_Gender = Gender(ValidateSet);
   
   % Construct a random analogue to the validation set, 
   % to see whether the classification tree performs significantly better than random chance
   Random_Gender = Gender(RandomSet);
   
   % This section of code calculates the confusion matrix for both the classified and random datasets
   True = 0; RandomTrue = 0; Conf = zeros(2); Misallocate = [];
   for v = 1:length(Predict_Gender)
      if strcmp(Predict_Gender{v},Truth_Gender{v})==1
         True = True + 1;
      else
         Misallocate = [Misallocate; [Titles((ValidateSet(v))) Truth_Gender{v} Predict_Gender{v} Gender((ValidateSet(v))) Location((ValidateSet(v))) Nationality((ValidateSet(v))) Author((ValidateSet(v)))]];
      end
      if strcmp(Random_Gender{v},Truth_Gender{v})==1
         RandomTrue = RandomTrue + 1;
      end
      if     strcmp(Predict_Gender{v},'Male')==1 & strcmp(Truth_Gender{v},'Male')==1;     Conf(1,1) = Conf(1,1) + 1;
      elseif strcmp(Predict_Gender{v},'Male')==1 & strcmp(Truth_Gender{v},'Female')==1;   Conf(1,2) = Conf(1,2) + 1;
      elseif strcmp(Predict_Gender{v},'Female')==1 & strcmp(Truth_Gender{v},'Male')==1;   Conf(2,1) = Conf(2,1) + 1;
      elseif strcmp(Predict_Gender{v},'Female')==1 & strcmp(Truth_Gender{v},'Female')==1; Conf(2,2) = Conf(2,2) + 1;
      end
   end
   
   % Display outputs of the process
   disp('== Gender ==')
   Conf = Conf./repmat(sum(Conf,1),size(Conf,1),1);
   Conf(isnan(Conf))=0
   Accuracy = True/length(Predict_Gender)
   ExpectedAccuracy = RandomTrue/length(Predict_Gender)
   ctree3 = ctree;
   
   % Display the classification tree visually
   view(ctree,'mode','graph');
   disp('Male')
   disp('Female')
   
   % Output the results to a CSV file
   Misallocate = [[{'Title','True gender','Misallocated gender','G','L','N','A'}]; Misallocate];
   cell2csv(['Misallocated_Genders_Splits_' num2str(MNS) '_Topics_' num2str(NumTopics) '_Years_'  num2str(YearRange(1)) '_' num2str(YearRange(2)) '.csv'],Misallocate,'_')
   
end