%% Feature Engineering
% Only select information available to participants and avoid variables
% with too many NaNs or with too many categories. Normalize ratings to
% remove indidividual biases

func = @(x) {(x - mean(x))./std(x)};                % normalize func
ft = table;                                         % initializ a table
ft.gender =  categorical(csv.gender);               % add genger
f = splitapply(@(x) {x ./ numel(x)}, csv.order, G); % normalize by group
ft.order = vertcat(f{:});                           % add normalized order
ft.samerace = categorical(csv.samerace);            % add same race
ft.race_o = categorical(csv.race_o);                % add partner race
f = csv.age_o - csv.age;                            % get age gap
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.agegap = vertcat(f{:});                          % add age gap
ft.field_cd = categorical(csv.field_cd);            % add field cd
ft.race = categorical(csv.race);                    % add participant race
ft.goal = categorical(csv.goal);                    % add goal
ft.date = categorical(csv.date);                    % add date
ft.go_out = categorical(csv.go_out);                % add go out
ft.sports = csv.sports;                             % add sports
ft.tvsports = csv.tvsports;                         % add tvsports
ft.exercise = csv.exercise;                         % add exercise
ft.dining = csv.dining;                             % add dining
ft.museums = csv.museums;                           % add museums
ft.art = csv.art;                                   % add art
ft.hiking = csv.hiking;                             % add hiking
ft.gaming = csv.gaming;                             % add gaming
ft.clubbing = csv.clubbing;                         % add clubbing
ft.reading = csv.reading;                           % add reading
ft.tv = csv.tv;                                     % add tv
ft.theater = csv.theater;                           % add theater
ft.movies = csv.movies;                             % add movies
ft.concerts = csv.concerts;                         % add concerts
ft.music = csv.music;                               % add music
ft.shopping = csv.shopping;                         % add shopping
ft.yoga = csv.yoga;                                 % add yoga
vars = csv.Properties.VariableNames;                % get var names
pref = csv(:,contains(vars,'1_1'));                 % subset pref
pref = table2array(pref);                           % convert to array
pref(isnan(pref)) = 0;                              % replace NaN with 0
pref = pref ./ sum(pref,2);                         % convert to 1-pt alloc
ft.attr1_1 = pref(:,1);                             % rescaled attr1_1
ft.sinc1_1 = pref(:,2);                             % rescaled sinc1_1
ft.intel1_1 = pref(:,3);                            % rescaled intel1_1
ft.fun1_1 = pref(:,4);                              % rescaled fun1_1
ft.amb1_1 =  pref(:,5);                             % rescaled amb1_1
ft.shar1_1 = pref(:,6);                             % rescaled shar1_1
f = csv.attr;                                       % get attr
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.attr = vertcat(f{:});                            % add normalized attr
f = csv.attr - csv.attr3_1;                         % get attr gap
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.attrgap = vertcat(f{:});                         % add attr gap
ft.attr3_1 = csv.attr3_1;                           % add attr3_1
f = csv.sinc;                                       % get sinc
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.sinc = vertcat(f{:});                            % add normalized sinc
f =  csv.sinc - csv.sinc3_1;                        % get sinc gap
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.sincgap = vertcat(f{:});                         % add normalized sinc
f = csv.intel;                                      % get intel
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.intel = vertcat(f{:});                           % add normalized intel
f = csv.intel - csv.intel3_1;                       % get intel gap
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.intelgap = vertcat(f{:});                        % normalized intel gap
f = csv.fun;                                        % get fun
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.fun = vertcat(f{:});                             % add normalized fun
f = csv.fun - csv.fun3_1;                           % get fun gap
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.fungap = vertcat(f{:});                          % normalized fun gap
f = csv.amb;                                        % get amb
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.amb = vertcat(f{:});                             % add normalized amb
f = csv.amb - csv.amb3_1;                           % get amb gap
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.ambgap = vertcat(f{:});                          % normalized amb gap
f = csv.shar;                                       % get shar
f(isnan(f)) = 0;                                    % replace NaN with 0
f = splitapply(func, f, G);                         % normalize by group
ft.shar = vertcat(f{:});                            % add normalized shar
ft.met = categorical(csv.met);                      % add met
ft.dec = categorical(csv.dec);                      % add yes/no decision

%% Partition Data
% Randomly partition data into 90% training and 10% holdout sets,
% preserving the class proportion of response variable, dec.

rng(1)                                              % for reproducibility
cv = cvpartition(ft.dec,'HoldOut',0.1);             % partition data
train = ft(training(cv),:);                         % for training
holdout = ft(test(cv),:);                           % for model evaluation

clearvars f ft func pref vars

