MLZ02_dpr_group_fits.m

Nonlinear fits of the group-level d' data from the MLSecond02 experiment

File: work/MLExper/MLSecond02/analysis/MLZ02_dpr_group_fits.m
1.2.1 2010-01-29 AP: test whether Y24 < Y18 for Group 1
1.2.0 2010-01-21 AP: z-tests based on bootstrap estimates of variance
1.1.0 2009-10-09 TH: Added the "new eleven-parameter model"
1.0.0 2009-09-04 AP: Wrote it, based on MLPilot02/anal/dpr_group_fits.m

Contents

Get started

cd(fullfile(MLSecond02_pathstr,'analysis')) ;
fprintf('\n\nExecuting MLZ02_dpr_group_fits on %s.\n\n',datestr(now)) ;
fprintf('cd %s\n',pwd) ;

clear all ;

Executing MLZ02_dpr_group_fits on 29-Jan-2010 17:44:36.

cd /Users/apetrov/a/r/w/work/MLExper/MLSecond02/analysis

Design parameters

Load them from the code that administered the experiment:

P = MLZ02_params(0) ;
design_params = P.design_params ;

N_sessions = design_params.max_session ;          % 6 sessions
blocks_session = design_params.blocks_session ;   % 8 blocks per session
  % Note: We're going to aggregate blocks two by two below.
  % So, the effective number of blocks per session is 4 rather than 8
blocks2_session = blocks_session / 2 ;
N_blocks = N_sessions * blocks_session ;
N_blocks2 = N_sessions * blocks2_session ;
trials_block = design_params.trials_block ;       % 104 trials per block
trials_block2 = 2*trials_block ;                  % 208 per double-block
N_trials = N_blocks * trials_block ;
group_descr = design_params.group_descr'  %#ok<*NOPTS>
deltas = design_params.deltas ;           % [11 8] = [easy difficult]
group_descr = 

    'FirstNeg'
    'SecondNeg'
    'FirstPos'
    'SecondPos'

Load the data

H_filename = fullfile(MLSecond02_pathstr,'data','H.mat') ;
if (exist(H_filename,'file'))
    fprintf('load %s \n\n',H_filename) ;
    load(H_filename) ;
else
    error('Cannot find %s.\n Run MLZ02_plot_dprime to create it if necessary.',...
          H_filename) ;
end

% Make sure all data sets in H are complete
N = [H.N] ;
assert(all(N==N_blocks)) ;
N_sbj = length(H) ;

gr = [H.group] ;
xtab1(gr')
load /Users/apetrov/a/r/w/work/MLExper/MLSecond02/data/H.mat 


   Value   Count  Percent  Cum_cnt  Cum_pct
-------------------------------------------
       1       5    25.00        5    25.00
       2       5    25.00       10    50.00
       3       5    25.00       15    75.00
       4       5    25.00       20   100.00
-------------------------------------------

Adjust dprime for sbj 325, Day 3, which is anomalously bad for this sbj.

The constants 0.95, 1.10, 0.60 were chosen by eye to make the corresponding learning curves smooth across Days 2-4. Crit2 and RTs are left alone. Sbj 325 was assigned to Group 3 (FirstPos).

sbj325 = find([H.sbj]==325) ;
day3 = (9:12) ;
H(sbj325).all_dprime2(day3) = H(sbj325).all_dprime2(day3) + 0.95 ;
H(sbj325).easy_dprime2(day3) = H(sbj325).easy_dprime2(day3) + 1.10 ;
H(sbj325).hard_dprime2(day3) = H(sbj325).hard_dprime2(day3) + 0.60 ;
%dpr2_sbj325=[H(sbj325).all_dprime2 H(sbj325).easy_dprime2 H(sbj325).hard_dprime2];
%plot(dpr2_sbj325,'.-');set(gca,'xtick',0:4:N_blocks2);axis([0 N_blocks2 0 2.5]);
clear sbj325 day3 dpr2_sbj325

Save the adjusted data for future use by MLZ01_dprfit_bootstrap

H_adjusted_filename = fullfile(MLSecond02_pathstr,'data','H_adjusted.mat') ;
if (exist(H_adjusted_filename,'file'))
    fprintf('%s already exists. Delete and re-run to replace it. \n\n',...
            H_adjusted_filename) ;
else
    fprintf('save %s \n\n',H_adjusted_filename) ;
    save(H_adjusted_filename,'H') ;
end
/Users/apetrov/a/r/w/work/MLExper/MLSecond02/data/H_adjusted.mat already exists. Delete and re-run to replace it. 

Time- and task-related variables -- See MLSecond02_params for details

bl = H(1).block2 ;        % [N_blocks2 x 1], blocks aggregated two by two
gT = (bl-.5) .* trials_block ;  % global time grid

% Generate XDATA struct by calling MLZ02_piecemeal_curve with no arguments
xdata = MLZ02_piecemeal_curve ;
assert(xdata.N_blocks == N_blocks2) ;         % sanity check
assert(xdata.trials_block == trials_block) ;
assert(max(abs(xdata.global_T - gT))==0) ;

xtick = xdata.xtick ;
i1 = xdata.test1_idx ;    % Segment 1: pre-test blocks  [ 1: 2]
i2 = xdata.train_idx ;    % Segment 1: training blocks  [ 3:18]
i3 = xdata.test2_idx ;    % Segment 1: post-test blocks [19:24]

Pack the dprime2 data into matrices

adpr2 = [H.all_dprime2] ;      % [N_blocks2 x N_subjects]
%acrit2 = [H.all_crit2] ;
edpr2= [H.easy_dprime2] ;
%ecrit2= [H.easy_crit2] ;
hdpr2= [H.hard_dprime2] ;
%hcrit2= [H.hard_crit2] ;

Subtract individual subjects' means to estimate within-sbj variance

madpr2_by_sbj = mean(adpr2) ;       % [1 x N_subjects]
adpr2_centered = adpr2 - repmat(madpr2_by_sbj,N_blocks2,1) ;
assert(max(abs(mean(adpr2_centered)))<1e-6)   % diachronic mean now 0 for each S

medpr2_by_sbj = mean(edpr2) ;       % [1 x N_subjects]
edpr2_centered = edpr2 - repmat(medpr2_by_sbj,N_blocks2,1) ;
assert(max(abs(mean(edpr2_centered)))<1e-6)   % diachronic mean now 0 for each S

mhdpr2_by_sbj = mean(hdpr2) ;       % [1 x N_subjects]
hdpr2_centered = hdpr2 - repmat(mhdpr2_by_sbj,N_blocks2,1) ;
assert(max(abs(mean(hdpr2_centered)))<1e-6)   % diachronic mean now 0 for each S

Aggregate the data into 4 group averages

There are 4 experimental groups: FirstNeg=1,SecondNeg=2,FirstPos=3,SecondPos=4

l_gr4 = {'Gr 1=1stN','Gr 2=2ndN','Gr 3=1stP','Gr 4=2ndP'} ; % legend
Ss4 = cell(4,1) ;
for k = 1:length(Ss4)
    Ss4{k} = find(gr==k) ;
    N_sbj_gr4(k) = length(Ss4{k}) ;                        %#ok<SAGROW>
    madpr2_gr4(:,k) = mean(adpr2(:,Ss4{k}),2) ;            %#ok<SAGROW>
    semadpr2_gr4(:,k) = std(adpr2_centered(:,Ss4{k}),0,2); %#ok<SAGROW>
    medpr2_gr4(:,k) = mean(edpr2(:,Ss4{k}),2) ;            %#ok<SAGROW>
    semedpr2_gr4(:,k) = std(edpr2_centered(:,Ss4{k}),0,2); %#ok<SAGROW>
    mhdpr2_gr4(:,k) = mean(hdpr2(:,Ss4{k}),2) ;            %#ok<SAGROW>
    semhdpr2_gr4(:,k) = std(hdpr2_centered(:,Ss4{k}),0,2); %#ok<SAGROW>
end
assert(isempty(intersect(Ss4{1},Ss4{2}))) ;   % Sanity check
assert(isempty(intersect(Ss4{1},Ss4{3}))) ;   % Sanity check
assert(isempty(intersect(Ss4{1},Ss4{4}))) ;   % Sanity check
assert(isempty(intersect(Ss4{2},Ss4{3}))) ;   % Sanity check
assert(isempty(intersect(Ss4{2},Ss4{4}))) ;   % Sanity check
assert(isempty(intersect(Ss4{3},Ss4{4}))) ;   % Sanity check

% within-sbj confidence intervals
alpha = .90 ;                      % confidence level
z_crit = norminv((1+alpha)/2) ;    % 1.64 for alpha=90%
CI_madpr2_gr4 = z_crit.*(semadpr2_gr4./repmat(sqrt(N_sbj_gr4),N_blocks2,1)) ;

Plot adprime2 for all 4 groups

clr = 'rbmg' ;      % Red=1stN, Blue=2ndN, Magenta=1stP, Green=2ndP
JTR4 = [-1 -.5 .5 1].*(trials_block/8) ;     % jitter for visibility
train_first_p = [true false true false] ;    % controls MarkerFaceColor
sym1 = 'osos' ;    % transfer order of motion: square=1st, circle=2nd
sym2 = 'soso' ;    % training order of motion: square=1st, circle=2nd
M = 2.5 ;  % max d'

clf
d = madpr2_gr4 ;   % plot all_dprime2 averaged into 4 groups
CI = CI_madpr2_gr4 ;
for k = 1:4
    hold on ;  % must be inside the loop
    t = gT + JTR4(k) ;
    C = clr(k) ;      % color for this group. Always remains consistent
    s1 = sym1(k) ;    % transfer symbol for this group
    s2 = sym2(k) ;    % training symbol for this group
    h = plot(...
        t(i1)  ,d(i1,k) ,[C s1 '-']   ... % 1: pre-test
       ,t(i2)  ,d(i2,k) ,[C s2 '-']   ... % 2: train
       ,t(i3)  ,d(i3,k) ,[C s1 '-']   ... % 3: post-test
       ) ;
    % Filled symbols demarkate groups training on first-order stimuli
    if (train_first_p(k))
        set(h,'MarkerFaceColor',C) ;
    %else  leave symbols open
    end
    % Error bars w/in Ss.  (This call contains an implicit 'hold off')
    errorbar1(t,d(:,k),CI(:,k),[C 'n']) ;   % no whiskers
end
hold off ; box on ;
clear d CI h

axis([0 N_trials 0 M]) ; grid on ;
set(gca,'xtick',xtick,'ytick',(0:ceil(M))) ;
xlabel('Trial') ; ylabel('d''') ;
title(sprintf('MLSecond02: %s (n=%d), %s (%d), %s (%d), %s (%d) '  ...
     ,l_gr4{1},N_sbj_gr4(1),l_gr4{2},N_sbj_gr4(2) ...
     ,l_gr4{3},N_sbj_gr4(3),l_gr4{4},N_sbj_gr4(4) ));

Average REFERENCE DIRECTION out to make two supergroups: First and Second

Based on visual inspection of the above plot, as well as knowledge of other data sets in our lab, the positive and negative directions of motion seem to yeild identical learning patterns. The red and magenta lines are right on top of each other. The blue and green lines seem equivalent up to multiplication by a constant factor. Thus, we are going to combine Group 1+3 into a (super)Group 1 and Groups 2+4 into sGroup 2.

1stN(1) + 1stP(3) --> First(1) ; 2ndN(2) + 2ndP(4) --> Second(2)
l_gr4 = {'Gr 1=1stN','Gr 2=2ndN','Gr 3=1stP','Gr 4=2ndP'} ; % old legend
l = {'Gr 1=First','Gr 2=Second'} ; % new legend

Ss2{1} = [Ss4{1} , Ss4{3}] ;
Ss2{2} = [Ss4{2} , Ss4{4}] ;
assert(isempty(intersect(Ss2{1},Ss2{2}))) ;   % Sanity check

N_sbj_gr2 = N_sbj_gr4(1:2) + N_sbj_gr4(3:4) ;
madpr2 = (madpr2_gr4(:,1:2)+madpr2_gr4(:,3:4))./2 ;
semadpr2 = (semadpr2_gr4(:,1:2)+semadpr2_gr4(:,3:4))./2 ;
medpr2 = (medpr2_gr4(:,1:2)+medpr2_gr4(:,3:4))./2 ;
semedpr2 = (semedpr2_gr4(:,1:2)+semedpr2_gr4(:,3:4))./2 ;
mhdpr2 = (mhdpr2_gr4(:,1:2)+mhdpr2_gr4(:,3:4))./2 ;
semhdpr2 = (semhdpr2_gr4(:,1:2)+semhdpr2_gr4(:,3:4))./2 ;

% within-sbj confidence intervals
CI_madpr2 = z_crit.*(semadpr2./repmat(sqrt(N_sbj_gr2),N_blocks2,1)) ;
CI_medpr2 = z_crit.*(semedpr2./repmat(sqrt(N_sbj_gr2),N_blocks2,1)) ;
CI_mhdpr2 = z_crit.*(semhdpr2./repmat(sqrt(N_sbj_gr2),N_blocks2,1)) ;

Plot adprime2 for the two (super)groups

clr = 'rb' ;      % Red=1stN, Blue=2ndN, Magenta=1stP, Green=2ndP
JTR2 = [-.5 .5].*(trials_block/8) ;     % jitter for visibility
train_first_p = [true false] ;        % controls MarkerFaceColor
sym1 = 'os' ;    % transfer order of motion: square=1st, circle=2nd
sym2 = 'so' ;    % training order of motion: square=1st, circle=2nd
M = 2.5 ;  % max d'

clf
d = madpr2 ;   % plot all_dprime2 averaged into 2 groups
CI = CI_madpr2 ;
for k = 1:2
    hold on ;  % must be inside the loop
    t = gT + JTR2(k) ;
    C = clr(k) ;      % color for this group. Always remains consistent
    s1 = sym1(k) ;    % transfer symbol for this group
    s2 = sym2(k) ;    % training symbol for this group
    h = plot(...
        t(i1) ,d(i1,k) ,[C s1 '-']   ... % 1: pre-test
       ,t(i2) ,d(i2,k) ,[C s2 '-']   ... % 2: train
       ,t(i3) ,d(i3,k) ,[C s1 '-']   ... % 3: post-test
       ) ;
    % Filled symbols demarkate groups training on first-order stimuli
    if (train_first_p(k))
        set(h,'MarkerFaceColor',C) ;
    %else  leave symbols open
    end
    % Error bars w/in Ss.  (This call contains an implicit 'hold off')
    errorbar1(t,d(:,k),CI(:,k),[C 'n']) ;   % no whiskers
end
hold off ; box on ;
clear d CI h

axis([0 N_trials 0 M]) ; grid on ;
set(gca,'xtick',xtick,'ytick',(0:.5:M)) ;
xlabel('Trial') ; ylabel('d''') ;
title(sprintf('MLSecond02: %s (n=%d), %s (n=%d) '  ...
     ,l{1},N_sbj_gr2(1),l{2},N_sbj_gr2(2) ));

Plot easy and hard d' separately

clr = 'rbrb' ;      % Red=1st, Blue=2nd; Repeat for Easy and Hard
train_first_p = [true false true false] ;    % controls MarkerFaceColor
sym1 = 'osos' ;    % transfer: square=1st, circle=2nd; Repeat Ez & Hd
sym2 = 'soso' ;    % training: square=1st, circle=2nd; Repeat Ez & Hd

clf
d = [medpr2 mhdpr2] ;   % [easy_dprime2 hard_dprime2], N_blocks2-by-4
CI = [CI_medpr2 CI_mhdpr2] ;
for k = 1:4
    hold on ;  % must be inside the loop
    t = gT + JTR4(k) ;
    C = clr(k) ;      % color for this group. Always remains consistent
    s1 = sym1(k) ;    % transfer symbol for this group
    s2 = sym2(k) ;    % training symbol for this group
    h = plot(...
        t(i1)  ,d(i1,k) ,[C s1 '-']   ... % 1: pre-test
       ,t(i2)  ,d(i2,k) ,[C s2 '-']   ... % 2: train
       ,t(i3)  ,d(i3,k) ,[C s1 '-']   ... % 3: post-test
       ) ;
    % Filled symbols demarkate groups training on first-order stimuli
    if (train_first_p(k))
        set(h,'MarkerFaceColor',C) ;
    %else  leave symbols open
    end

    % Error bars w/in Ss.  (This call contains an implicit 'hold off')
    errorbar1(t,d(:,k),CI(:,k),[C 'n']) ;   % no whiskers
end
hold off ; box on ;
clear d CI h

axis([0 N_trials 0 M]) ; grid on ;
set(gca,'xtick',xtick,'ytick',(0:.5:M)) ;
xlabel('Trial') ; ylabel('d''') ;
title(sprintf('MLSecond02: %s (n=%d), %s (n=%d). Easy and difficult delta ' ...
     ,l{1},N_sbj_gr2(1),l{2},N_sbj_gr2(2) ));

Prepare to run MLZ02_lsqcurvefit: Saturated model

main_ydata = [medpr2 mhdpr2] ;
main_ydata_CI = [CI_medpr2 CI_mhdpr2] ;  % within Ss

% Group interpretation -- index the columns of main_ydata and rows of params
G.EzGr1 = 1 ;
G.EzGr2 = 2 ;
G.HdGr1 = 3 ;
G.HdGr2 = 4 ;
G.descr = {'EzGr1', 'EzGr2', 'HdGr1', 'HdGr2'} ;

% Problem struct for fitting the saturated model via MLZ02_lsqcurvefit.
% Subsequent reduced models will be built on this basis
saturated_problem = MLZ02_lsqcurvefit ;   % default struct
saturated_problem.comment = 'Fully saturated model: 4*8 params total' ;
saturated_problem.group_idx = G ;

saturated_problem.xdata = xdata ;        % generated by MLZ02_piecemeal_curve
saturated_problem.ydata = main_ydata ;   % [N_blocks2 x 4]

% Parameter interpetation. See MLZ02_piecemeal_curve for details.
I = xdata.params_idx ;
% I.Y1 = 1 ;      % test1_Ybeg
% I.Y2 = 2 ;      % test1_Yend
% I.Y3 = 3 ;      % train_Ybeg
% I.Y18 = 4 ;     % train_Yend
% I.Y19 = 5 ;     % test2_Ybeg
% I.Y24 = 6 ;     % test2_Yend
% I.Tau = 7 ;     % train_tau
% I.Tau2 = 8 ;    % test2_tau

% Lower and Upper bounds for the parameter search
lb1 = NaN(1,8) ;
lb1([I.Y1 I.Y2 I.Y3 I.Y18 I.Y19 I.Y24]) = 0 ;  % min d'
lb1([I.Tau I.Tau2]) = 10 ;                     % min time constant (in trials)

ub1 = NaN(1,8) ;
ub1([I.Y1 I.Y2 I.Y3 I.Y18 I.Y19 I.Y24]) = 4 ;  % max d'
ub1([I.Tau I.Tau2]) = 10000 ;                  % max time constant (in trials)

saturated_problem.lb_x = repmat(lb1,4,1) ;
saturated_problem.ub_x = repmat(ub1,4,1) ;

% Start the search with values taken from main ydata
main_params0 = NaN(4,8) ;      % 4 groups x 8 parameters each
main_params0(:,I.Y1)  = main_ydata(1,:)' ;
main_params0(:,I.Y2)  = main_ydata(2,:)' ;
main_params0(:,I.Y3)  = main_ydata(3,:)' ;
main_params0(:,I.Y18) = mean(main_ydata(16:18,:))' ;
main_params0(:,I.Y19) = main_ydata(19,:)' ;
main_params0(:,I.Y24) = mean(main_ydata(23:24,:))' ;
main_params0(:,I.Tau) = 1600 ;
main_params0(:,I.Tau2)= 150 ;
saturated_problem.params0 = main_params0 ;
saturated_problem.x0 = saturated_problem.param2vect(main_params0)

% Optimization options. See optimset('lsqnonlin') for details
%saturated_problem.options.Display = 'iter' ;  % verbose optimization

% R-squared utility
%subsref1 = @(vect,idx) (vect(idx)) ;   % now in utils/general
Rsq = @(x,y) (subsref1(corrcoef(x(:),y(:)),2)^2) ;
saturated_problem = 

         comment: 'Fully saturated model: 4*8 params total'
           xdata: [1x1 struct]
           ydata: [24x4 double]
      vect2param: @(x)(x)
      param2vect: @(p)(p)
    vector_names: {'Y1'  'Y2'  'Y3'  'Y18'  'Y19'  'Y24'  'tau'  'tau2'}
              x0: [4x8 double]
         params0: [4x8 double]
            lb_x: [4x8 double]
            ub_x: [4x8 double]
         options: [1x1 struct]
       group_idx: [1x1 struct]

Fit the saturated model

saturated_fit = MLZ02_lsqcurvefit(saturated_problem)   % <-- Sic!

fprintf('\nGroup:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 \n') ;
for k = 1:4
    p = saturated_fit.opt_params(k,:) ;
    fprintf('%s: %5.2f %5.2f   %5.2f %5.2f   %5.2f %5.2f   %5d %5d \n' ...
           ,G.descr{k} ...
           ,p(I.Y1),p(I.Y2), p(I.Y3),p(I.Y18), p(I.Y19),p(I.Y24)   ...
           ,round(p(I.Tau)), round(p(I.Tau2)) ) ;
end
saturated_fit = 

       comment: 'Fully saturated model: 4*8 params total'
         opt_x: [4x8 double]
    opt_params: [4x8 double]
          yhat: [24x4 double]
          RMSE: 0.0888
            R2: 0.9218
      exitflag: 3
        output: [1x1 struct]


Group:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 
EzGr1:  0.98  1.35    1.27  2.01    1.16  1.67    1369   118 
EzGr2:  1.05  1.39    1.18  1.79    1.86  1.82     756    10 
HdGr1:  0.81  0.96    0.96  1.58    0.89  1.29    7479   240 
HdGr2:  0.82  1.04    0.93  1.38    1.27  1.38    1539   332 

Plot the fit of the saturated model

clf
d = saturated_problem.ydata ;
CI = [CI_medpr2 CI_mhdpr2] ;
f = saturated_fit.yhat ;
for k = 1:4
    hold on ;  % must be inside the loop
    t = gT + JTR4(k) ;
    C = clr(k) ;      % color for this group. Always remains consistent
    s1 = sym1(k) ;    % transfer symbol for this group
    s2 = sym2(k) ;    % training symbol for this group
    h = plot(...
        t(i1)  ,d(i1,k) ,[C s1]   ... % 1: pre-test data
       ,t(i1)  ,f(i1,k) ,[C '-']  ... % 1: pre-test fit
       ,t(i2)  ,d(i2,k) ,[C s2]   ... % 2: train data
       ,t(i2)  ,f(i2,k) ,[C '-']  ... % 2: train fit
       ,t(i3)  ,d(i3,k) ,[C s1]   ... % 3: post-test data
       ,t(i3)  ,f(i3,k) ,[C '-']  ... % 3: post-test fit
       ) ;
    % Filled symbols demarkate groups training on first-order stimuli
    if (train_first_p(k))
        set(h,'MarkerFaceColor',C) ;
    %else  leave symbols open
    end
    % Error bars w/in Ss.  (This call contains an implicit 'hold off')
    errorbar1(t,d(:,k),CI(:,k),[C 'n']) ;   % no whiskers
end
hold off ; box on ;
clear d CI h f

axis([0 N_trials 0 M]) ; grid on ;
set(gca,'xtick',xtick,'ytick',(0:.5:M)) ;
xlabel('Trial') ; ylabel('d''') ;
title(sprintf('Saturated model: R2=%.3f, RMSE=%.4f, 32 params ' ...
     ,saturated_fit.R2 ,saturated_fit.RMSE ));

Saturated model with common time constants

The time constants tau are poorly constrained by the data. It should be easy to fit all four groups with the same Tau and Tau2. The Yxx params are still separate for each group. Thus this model has 26=4*6+2 params.

% Representation scheme: X is a 1x26 vector. X(25)=Tau, X(26)=Tau2.
saturY_cmnTau_vector_names = { ...
    'EzGr1Y1' 'EzGr1Y2' 'EzGr1Y3' 'EzGr1Y18' 'EzGr1Y19' 'EzGr1Y24' ...
    'EzGr2Y1' 'EzGr2Y2' 'EzGr2Y3' 'EzGr2Y18' 'EzGr2Y19' 'EzGr2Y24' ...
    'HdGr1Y1' 'HdGr1Y2' 'HdGr1Y3' 'HdGr1Y18' 'HdGr1Y19' 'HdGr1Y24' ...
    'HdGr2Y1' 'HdGr2Y2' 'HdGr2Y3' 'HdGr2Y18' 'HdGr2Y19' 'HdGr2Y24' ...
    'tau' 'tau2' } ;

saturY_cmnTau_vect2param = @(x) ...
    ([x( 1: 6) x(25) x(26) ...  % Gr 1: EzGr1
     ;x( 7:12) x(25) x(26) ...  % Gr 2: EzGr2
     ;x(13:18) x(25) x(26) ...  % Gr 3: HdGr1
     ;x(19:24) x(25) x(26) ]) ; % Gr 4: HdGr2

saturY_cmnTau_param2vect = @(p) ...
    ([p(1,1:6) p(2,1:6) p(3,1:6) p(4,1:6) ...  % Group-specific Yxx
     ,p(1,7) p(1,8) ]) ;                       % Common Tau and Tau2

% Construct a new problem structure based on saturated_problem:
saturY_cmnTau_problem = saturated_problem ;
saturY_cmnTau_problem.comment = 'Saturated Yxx, common Tau''s' ;
saturY_cmnTau_problem.vect2param = saturY_cmnTau_vect2param ;
saturY_cmnTau_problem.param2vect = saturY_cmnTau_param2vect ;
saturY_cmnTau_problem.vector_names = saturY_cmnTau_vector_names ;

% Start the new search from saturated_fit.opt_params:
x = saturY_cmnTau_param2vect(saturated_fit.opt_params) ;
x(25) = 1600 ;    % guess for the common Tau
x(26) =  150 ;    % guess for the common Tau2
saturY_cmnTau_problem.x0 = x ;

p = saturY_cmnTau_vect2param(x) ;
saturY_cmnTau_problem.params0 = p ;
assert(all(x==saturY_cmnTau_param2vect(p))) ;  % Sanity check

% Inherit the bounds from saturated_problem:
p = saturated_problem.vect2param(saturated_problem.lb_x) ; % canonicalize
x = saturY_cmnTau_param2vect(p) ;
assert(all(all(p==saturY_cmnTau_vect2param(x)))) ;  % Sanity check
saturY_cmnTau_problem.lb_x = x ;

p = saturated_problem.vect2param(saturated_problem.ub_x) ; % canonicalize
x = saturY_cmnTau_param2vect(p) ;
assert(all(all(p==saturY_cmnTau_vect2param(x)))) ;  % Sanity check
saturY_cmnTau_problem.ub_x = x           %#ok<NOPTS>
saturY_cmnTau_problem = 

         comment: 'Saturated Yxx, common Tau's'
           xdata: [1x1 struct]
           ydata: [24x4 double]
      vect2param: @(x)([x(1:6),x(25),x(26);x(7:12),x(25),x(26);x(13:18),x(25),x(26);x(19:24),x(25),x(26)])
      param2vect: @(p)([p(1,1:6),p(2,1:6),p(3,1:6),p(4,1:6),p(1,7),p(1,8)])
    vector_names: {1x26 cell}
              x0: [1x26 double]
         params0: [4x8 double]
            lb_x: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10]
            ub_x: [4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 10000 10000]
         options: [1x1 struct]
       group_idx: [1x1 struct]

Fit the saturated model with common time constants

saturY_cmnTau_fit = MLZ02_lsqcurvefit(saturY_cmnTau_problem)   %#ok<NOPTS>

fprintf('\nGroup:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 \n') ;
for k = 1:4
    p = saturY_cmnTau_fit.opt_params(k,:) ;
    fprintf('%s: %5.2f %5.2f   %5.2f %5.2f   %5.2f %5.2f   %5d %5d \n' ...
           ,G.descr{k} ...
           ,p(I.Y1),p(I.Y2), p(I.Y3),p(I.Y18), p(I.Y19),p(I.Y24)   ...
           ,round(p(I.Tau)), round(p(I.Tau2)) ) ;
end
saturY_cmnTau_fit = 

       comment: 'Saturated Yxx, common Tau's'
         opt_x: [1x26 double]
    opt_params: [4x8 double]
          yhat: [24x4 double]
          RMSE: 0.0918
            R2: 0.9165
      exitflag: 3
        output: [1x1 struct]


Group:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 
EzGr1:  0.98  1.35    1.29  2.02    1.16  1.67    1598   141 
EzGr2:  1.05  1.39    1.27  1.84    1.85  1.82    1598   141 
HdGr1:  0.81  0.96    0.89  1.51    0.87  1.26    1598   141 
HdGr2:  0.82  1.04    0.93  1.38    1.27  1.37    1598   141 

Significance test for nested multiple regression models

F-test of nested multiple regression models (see Equation on p. 542 in Howell, D. C. (1992), "Statistical Methods for Psychology", 3rd Ed.)

                (N-f-1)*(R2f-R2r)
F(f-r,N-f-1) = -------------------
                  (f-r)*(1-R2f)

N is the number of observations, R2F and R2R are the squared multiple correlations for the full and reduced models, respectively. DF_F and DF_R are the corresponding degrees of freedom. When not specified, the reduced model defaults to zero and thus the function calculates a test of whether R2F is significantly greater than zero. When two models are specified, the test is whether the increment of R2 is significant. See utils/R2signif.m for details.

Strictly speaking, this test is mathematically impeccable only for linear regression, but we're going to use it regardless. With the exception of the two tau's, our model is (quasi)linear in the parameters.

% Test the transition saturated_problem --> saturY_cmnTau_problem:
N_data_points = numel(main_ydata) ;   % 96 independent observations
Mf = saturated_fit ;       % full model
Mr = saturY_cmnTau_fit ;   % reduced model
df_f = numel(Mf.opt_x) ;   % degrees of freedom (# params) full model
df_r = numel(Mr.opt_x) ;   % degrees of freedom (# params) reduced model
[F,p] = R2signif(N_data_points,Mf.R2,df_f,Mr.R2,df_r) ;
fprintf('Full:         R2=%.4f, df=%2d  (%s)\n',Mf.R2,df_f,Mf.comment) ;
fprintf('Reduced:      R2=%.4f, df=%2d  (%s)\n',Mr.R2,df_r,Mr.comment) ;
fprintf('Significance: F(%d,%d)=%.4f, p=%.8f\n' ...
       , df_f-df_r, N_data_points-df_f-1, F, p) ;

% Conclusion: The drop in R2 (.9218 --> .9165) is not statistically
% significant and more than justifies the elimination of 6 free parameters.
Full:         R2=0.9218, df=32  (Fully saturated model: 4*8 params total)
Reduced:      R2=0.9165, df=26  (Saturated Yxx, common Tau's)
Significance: F(6,63)=0.7080, p=0.64433546

Plot the fit of the saturated model with common time constants

clf
d = saturY_cmnTau_problem.ydata ;
CI = [CI_medpr2 CI_mhdpr2] ;
f = saturY_cmnTau_fit.yhat ;
for k = 1:4
    hold on ;  % must be inside the loop
    t = gT + JTR4(k) ;
    C = clr(k) ;      % color for this group. Always remains consistent
    s1 = sym1(k) ;    % transfer symbol for this group
    s2 = sym2(k) ;    % training symbol for this group
    h = plot(...
        t(i1)  ,d(i1,k) ,[C s1]   ... % 1: pre-test data
       ,t(i1)  ,f(i1,k) ,[C '-']  ... % 1: pre-test fit
       ,t(i2)  ,d(i2,k) ,[C s2]   ... % 2: train data
       ,t(i2)  ,f(i2,k) ,[C '-']  ... % 2: train fit
       ,t(i3)  ,d(i3,k) ,[C s1]   ... % 3: post-test data
       ,t(i3)  ,f(i3,k) ,[C '-']  ... % 3: post-test fit
       ) ;
    % Filled symbols demarkate groups training on first-order stimuli
    if (train_first_p(k))
        set(h,'MarkerFaceColor',C) ;
    %else  leave symbols open
    end
    % Error bars w/in Ss.  (This call contains an implicit 'hold off')
    errorbar1(t,d(:,k),CI(:,k),[C 'n']) ;   % no whiskers
end
hold off ; box on ;
clear d CI h f

axis([0 N_trials 0 M]) ; grid on ;
set(gca,'xtick',xtick,'ytick',(0:.5:M)) ;
xlabel('Trial') ; ylabel('d''') ;
title(sprintf('Saturated Yxx, common taus: R2=%.3f, RMSE=%.4f, 26 params ' ...
     ,saturY_cmnTau_fit.R2 ,saturY_cmnTau_fit.RMSE ));

Proportionality between Easy and Hard d'

For both groups, the Yxx parameters for the Easy delta are proportional to that for the Hard delta. The ratio is ~1.345 and is the same for both groups:

p = saturY_cmnTau_fit.opt_params ;
p = p(1:2,:)./p(3:4,:)    %#ok<NOPTS>
f = geomean(p(:,1:6),2)   %#ok<NOPTS>
geomean(f)
p =

    1.2087    1.3982    1.4476    1.3426    1.3375    1.3296    1.0000    1.0000
    1.2810    1.3292    1.3654    1.3368    1.4578    1.3295    1.0000    1.0000


f =

    1.3420
    1.3489


ans =

    1.3454

Independent-group model with Easy/Hard proportionality

The Yxx for the Easy delta in each group is proportional to the Yxx for the Hard delta in the same group. The two groups have separate hard Yxx params. The coefficient of proportionality k is the same for both groups. The time constants Tau and Tau2 are also the same. Total number of params: 6+6+2+1=15

% Representation scheme: X is a 1x15 vector. X(13)=k, X(14)=Tau, X(15)=Tau2.
indepGr_cmnKTau_vector_names = { ...
    'HdGr1Y1' 'HdGr1Y2' 'HdGr1Y3' 'HdGr1Y18' 'HdGr1Y19' 'HdGr1Y24' ...
    'HdGr2Y1' 'HdGr2Y2' 'HdGr2Y3' 'HdGr2Y18' 'HdGr2Y19' 'HdGr2Y24' ...
    'k'       'tau'     'tau2' } ;
indepGr_K_idx = 13 ;

indepGr_cmnKTau_vect2param = @(x) ...
    ([x(13).*x(1: 6) x(14) x(15) ...  % Gr 1: EzGr1
     ;x(13).*x(7:12) x(14) x(15) ...  % Gr 2: EzGr2
     ;       x(1: 6) x(14) x(15) ...  % Gr 3: HdGr1
     ;       x(7:12) x(14) x(15) ]) ; % Gr 4: HdGr2

indepGr_cmnKTau_param2vect = @(p) ...
    ([p(3,1:6) p(4,1:6)           ...        % HdGr1_Yxx  HdGr2_Yxx
     ,geomean([geomean(p(1,1:6)./p(3,1:6))   ... % geomean([Gr1_k,Gr2_k])
              ,geomean(p(2,1:6)./p(4,1:6))]) ...
     ,p(1,7) p(1,8) ]) ;                     % Common Tau and Tau2

% Construct a new problem structure based on saturated_problem:
indepGr_cmnKTau_problem = saturated_problem ;
indepGr_cmnKTau_problem.comment = 'Group-specific Yxx, common k & Tau''s' ;
indepGr_cmnKTau_problem.vect2param = indepGr_cmnKTau_vect2param ;
indepGr_cmnKTau_problem.param2vect = indepGr_cmnKTau_param2vect ;
indepGr_cmnKTau_problem.vector_names = indepGr_cmnKTau_vector_names ;

% Start the new search from saturY_cmnTau_fit.opt_params:
x = indepGr_cmnKTau_param2vect(saturY_cmnTau_fit.opt_params) ;
indepGr_cmnKTau_problem.x0 = x ;

p = indepGr_cmnKTau_vect2param(x) ;
indepGr_cmnKTau_problem.params0 = p ;
assert(all(x==indepGr_cmnKTau_param2vect(p))) ;  % Sanity check

% Inherit the bounds from saturated_problem:
p = saturated_problem.vect2param(saturated_problem.lb_x) ;  % canonicalize
x = indepGr_cmnKTau_param2vect(p) ;
x(indepGr_K_idx) = 1.0 ;     % lower bound on k. This mandates that EzYxx>=HdYxxx
assert(all(all(p==indepGr_cmnKTau_vect2param(x)))) ;  % Sanity check
indepGr_cmnKTau_problem.lb_x = x ;

p = saturated_problem.vect2param(saturated_problem.ub_x) ;  % canonicalize
x = indepGr_cmnKTau_param2vect(p) ;
assert(all(all(p==indepGr_cmnKTau_vect2param(x)))) ;  % Sanity check
x(indepGr_K_idx) = 2.0 ;     % upper bound on k
indepGr_cmnKTau_problem.ub_x = x      %#ok<NOPTS>

% Optimization options. See optimset('lsqnonlin') for details
%indepGr_cmnKTau_problem.options.Display = 'iter' ;  % verbose optimization
indepGr_cmnKTau_problem = 

         comment: 'Group-specific Yxx, common k & Tau's'
           xdata: [1x1 struct]
           ydata: [24x4 double]
      vect2param: [1x1 function_handle]
      param2vect: [function_handle]
    vector_names: {1x15 cell}
              x0: [1x15 double]
         params0: [4x8 double]
            lb_x: [0 0 0 0 0 0 0 0 0 0 0 0 1 10 10]
            ub_x: [4 4 4 4 4 4 4 4 4 4 4 4 2 10000 10000]
         options: [1x1 struct]
       group_idx: [1x1 struct]

Fit the independent-group model with Easy/Hard proportionality

indepGr_cmnKTau_fit = MLZ02_lsqcurvefit(indepGr_cmnKTau_problem)   %#ok<NOPTS>

fprintf('\nGroup:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 \n') ;
for k = 1:4
    p = indepGr_cmnKTau_fit.opt_params(k,:) ;
    fprintf('%s: %5.2f %5.2f   %5.2f %5.2f   %5.2f %5.2f   %5d %5d \n' ...
           ,G.descr{k} ...
           ,p(I.Y1),p(I.Y2), p(I.Y3),p(I.Y18), p(I.Y19),p(I.Y24)   ...
           ,round(p(I.Tau)), round(p(I.Tau2)) ) ;
end
fprintf('EzYxx/HdYxx = k = %.4f \n\n',indepGr_cmnKTau_fit.opt_x(indepGr_K_idx)) ;

% Test the transition saturY_cmnTau_problem --> indepGr_cmnKTau_problem
Mf = saturY_cmnTau_fit ;   % full model
Mr = indepGr_cmnKTau_fit ; % reduced model
df_f = numel(Mf.opt_x) ;   % degrees of freedom (# params) full model
df_r = numel(Mr.opt_x) ;   % degrees of freedom (# params) reduced model
[F,p] = R2signif(N_data_points,Mf.R2,df_f,Mr.R2,df_r) ;
fprintf('Full:         R2=%.4f, df=%2d  (%s)\n',Mf.R2,df_f,Mf.comment) ;
fprintf('Reduced:      R2=%.4f, df=%2d  (%s)\n',Mr.R2,df_r,Mr.comment) ;
fprintf('Significance: F(%d,%d)=%.4f, p=%.8f\n' ...
       , df_f-df_r, N_data_points-df_f-1, F, p) ;

% Conclusion: The drop in R2 (.9165 --> .9140) is not statistically
% significant and more than justifies the elimination of 11 free params!
indepGr_cmnKTau_fit = 

       comment: 'Group-specific Yxx, common k & Tau's'
         opt_x: [1x15 double]
    opt_params: [4x8 double]
          yhat: [24x4 double]
          RMSE: 0.0931
            R2: 0.9140
      exitflag: 3
        output: [1x1 struct]


Group:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 
EzGr1:  1.02  1.33    1.26  2.03    1.17  1.68    1561   140 
EzGr2:  1.07  1.39    1.26  1.85    1.80  1.83    1561   140 
HdGr1:  0.76  0.98    0.93  1.50    0.87  1.25    1561   140 
HdGr2:  0.79  1.03    0.93  1.37    1.33  1.35    1561   140 
EzYxx/HdYxx = k = 1.3507 

Full:         R2=0.9165, df=26  (Saturated Yxx, common Tau's)
Reduced:      R2=0.9140, df=15  (Group-specific Yxx, common k & Tau's)
Significance: F(11,69)=0.1891, p=0.99775495

Plot the fit of the independent-group model with Easy/Hard proportionality

clf
d = indepGr_cmnKTau_problem.ydata ;
CI = [CI_medpr2 CI_mhdpr2] ;
f = indepGr_cmnKTau_fit.yhat ;
for k = 1:4
    hold on ;  % must be inside the loop
    t = gT + JTR4(k) ;
    C = clr(k) ;      % color for this group. Always remains consistent
    s1 = sym1(k) ;    % transfer symbol for this group
    s2 = sym2(k) ;    % training symbol for this group
    h = plot(...
        t(i1)  ,d(i1,k) ,[C s1]   ... % 1: pre-test data
       ,t(i1)  ,f(i1,k) ,[C '-']  ... % 1: pre-test fit
       ,t(i2)  ,d(i2,k) ,[C s2]   ... % 2: train data
       ,t(i2)  ,f(i2,k) ,[C '-']  ... % 2: train fit
       ,t(i3)  ,d(i3,k) ,[C s1]   ... % 3: post-test data
       ,t(i3)  ,f(i3,k) ,[C '-']  ... % 3: post-test fit
       ) ;
    % Filled symbols demarkate groups training on first-order stimuli
    if (train_first_p(k))
        set(h,'MarkerFaceColor',C) ;
    %else  leave symbols open
    end
    % Error bars w/in Ss.  (This call contains an implicit 'hold off')
    errorbar1(t,d(:,k),CI(:,k),[C 'n']) ;   % no whiskers
end
hold off ; box on ;
clear d CI h f

axis([0 N_trials 0 M]) ; grid on ;
set(gca,'xtick',xtick,'ytick',(0:.5:M)) ;
xlabel('Trial') ; ylabel('d''') ;
title(sprintf('Group-specific Yxx, common k & taus: R2=%.3f, RMSE=%.4f, 15 params ' ...
     ,indepGr_cmnKTau_fit.R2 ,indepGr_cmnKTau_fit.RMSE ));

Twelve-parameter model: Common Y1, Y2, Y3

Our pilot experiment has been remarkably successful in equalizing the initial performance level in the two groups. Constrain the Y1, Y2, and Y3 parameters to be common in the two groups. K, tau, tau2 remain shared. Total number of params: 3+2*3+1+2=12

% Representation scheme: X is a 1x12 vector:
% x(1:3) stores [Y1 Y2 Y3] for both Hard groups
% x(4:6) stores [Y18 Y19 Y24] for HdGr1
% x(7:9) stores [Y18 Y19 Y24] for HdGr2
% x(10) stores k = EzYxx/HdYxx for both groups
% x(11) and x(12) store Tau and Tau2 for both groups
param12_vector_names = { ...
    'HdY1'     'HdY2'     'HdY3'     ...   % 1:3
    'HdGr1Y18' 'HdGr1Y19' 'HdGr1Y24' ...   % 4:6
    'HdGr2Y18' 'HdGr2Y19' 'HdGr2Y24' ...   % 7:9
    'k'        'tau'      'tau2'     } ;   %10:12

param12_vect2param = @(x) ...
    ([ x(10).*x(1:3) ...  % EzGr1: [Y1  Y2  Y3 ]
      ,x(10).*x(4:6) ...  % EzGr1: [Y18 Y19 Y24]
      ,x(11), x(12)  ...  % EzGr1: [Tau Tau2]
     ; x(10).*x(1:3) ...  % EzGr2: [Y1  Y2  Y3 ]
      ,x(10).*x(7:9) ...  % EzGr2: [Y18 Y19 Y24]
      ,x(11), x(12)  ...  % EzGr2: [Tau Tau2]
     ;        x(1:3) ...  % HdGr1: [Y1  Y2  Y3 ]
      ,       x(4:6) ...  % HdGr1: [Y18 Y19 Y24]
      ,x(11), x(12)  ...  % HdGr2: [Tau Tau2]
     ;        x(1:3) ...  % HdGr2: [Y1  Y2  Y3 ]
      ,       x(7:9) ...  % HdGr2: [Y18 Y19 Y24]
      ,x(11), x(12)  ]);  % HdGr2: [Tau Tau2]

param12_param2vect = @(p) ...
    ([p(3,1:3) ...    % [Y1  Y2  Y3] for both Hard groups
     ,p(3,4:6) ...    % [Y18 Y19 Y24] for HdGr1
     ,p(4,4:6) ...    % [Y18 Y19 Y24] for HdGr2
     ,geomean([geomean(p(1,1:6)./p(3,1:6))   ... % geomean([Gr1_k,Gr2_k])
              ,geomean(p(2,1:6)./p(4,1:6))]) ...
     ,p(1,7) p(1,8) ]) ;                         % Common Tau and Tau2

% Construct a new problem structure based on saturated_problem:
param12_problem = saturated_problem ;
param12_problem.comment = 'Specific Y18,Y19,Y24. Common Y1,Y2,Y3, k, Tau,Tau2' ;
param12_problem.vect2param = param12_vect2param ;
param12_problem.param2vect = param12_param2vect ;
param12_problem.vector_names = param12_vector_names ;

% Start the new search from saturY_cmnTau_fit.opt_params:
x = param12_param2vect(saturY_cmnTau_fit.opt_params) ;
param12_problem.x0 = x ;

p = param12_vect2param(x) ;
param12_problem.params0 = p ;
assert(all(x==param12_param2vect(p))) ;  % Sanity check

% Inherit the bounds from saturated_problem:
p = saturated_problem.vect2param(saturated_problem.lb_x) ;  % canonicalize
x = param12_param2vect(p) ;
x(10) = 1.0 ;     % lower bound on k. This mandates that EzYxx>=HdYxxx
assert(max(max(abs(p-param12_vect2param(x))))<1e-6) ; % Sanity check
param12_problem.lb_x = x ;

p = saturated_problem.vect2param(saturated_problem.ub_x) ;  % canonicalize
x = param12_param2vect(p) ;
assert(max(max(abs(p-param12_vect2param(x))))<1e-6) ; % Sanity check
x(10) = 2.0 ;     % upper bound on k
param12_problem.ub_x = x      %#ok<NOPTS>

% Optimization options. See optimset('lsqnonlin') for details
%param12_problem.options.Display = 'iter' ;  % verbose optimization
param12_problem = 

         comment: 'Specific Y18,Y19,Y24. Common Y1,Y2,Y3, k, Tau,Tau2'
           xdata: [1x1 struct]
           ydata: [24x4 double]
      vect2param: [function_handle]
      param2vect: [function_handle]
    vector_names: {1x12 cell}
              x0: [0.8134 0.9628 0.8900 1.5079 0.8710 1.2586 1.3773 1.2676 1.3664 1.3454 1.5977e+03 141.1831]
         params0: [4x8 double]
            lb_x: [0 0 0 0 0 0 0 0 0 1 10 10]
            ub_x: [4 4 4 4 4 4 4 4 4 2 10000 10000]
         options: [1x1 struct]
       group_idx: [1x1 struct]

Fit the twelve-parameter model

param12_fit = MLZ02_lsqcurvefit(param12_problem)   %#ok<NOPTS>

fprintf('\nGroup:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 \n') ;
for k = 1:4
    p = param12_fit.opt_params(k,:) ;
    fprintf('%s: %5.2f %5.2f   %5.2f %5.2f   %5.2f %5.2f   %5d %5d \n' ...
           ,G.descr{k} ...
           ,p(I.Y1),p(I.Y2), p(I.Y3),p(I.Y18), p(I.Y19),p(I.Y24)   ...
           ,round(p(I.Tau)), round(p(I.Tau2)) ) ;
end
fprintf('EzYxx/HdYxx = k = %.4f \n\n',param12_fit.opt_x(10)) ;

% Test the transition indepGr_cmnKTau_problem --> param12_problem
Mf = indepGr_cmnKTau_fit ; % full model
Mr = param12_fit ;         % reduced model
df_f = numel(Mf.opt_x) ;   % degrees of freedom (# params) full model
df_r = numel(Mr.opt_x) ;   % degrees of freedom (# params) reduced model
[F,p] = R2signif(N_data_points,Mf.R2,df_f,Mr.R2,df_r) ;
fprintf('Full:         R2=%.4f, df=%2d  (%s)\n',Mf.R2,df_f,Mf.comment) ;
fprintf('Reduced:      R2=%.4f, df=%2d  (%s)\n',Mr.R2,df_r,Mr.comment) ;
fprintf('Significance: F(%d,%d)=%.4f, p=%.8f\n' ...
       , df_f-df_r, N_data_points-df_f-1, F, p) ;

% Conclusion: The drop in R2 (.9140 --> .9135) is not statistically
% significant and more than justifies the elimination of 3 free params.
% The twelve-parameter model is a good candidate for being the final model.
% As of 2009-10-09, however, it is superseded by the "New Eleven-parameter
% model.
param12_fit = 

       comment: 'Specific Y18,Y19,Y24. Common Y1,Y2,Y3, k, Tau,Tau2'
         opt_x: [0.7762 1.0085 0.9316 1.4999 0.8653 1.2456 1.3677 1.3326 1.3525 1.3508 1.5622e+03 140.1366]
    opt_params: [4x8 double]
          yhat: [24x4 double]
          RMSE: 0.0934
            R2: 0.9135
      exitflag: 3
        output: [1x1 struct]


Group:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 
EzGr1:  1.05  1.36    1.26  2.03    1.17  1.68    1562   140 
EzGr2:  1.05  1.36    1.26  1.85    1.80  1.83    1562   140 
HdGr1:  0.78  1.01    0.93  1.50    0.87  1.25    1562   140 
HdGr2:  0.78  1.01    0.93  1.37    1.33  1.35    1562   140 
EzYxx/HdYxx = k = 1.3508 

Full:         R2=0.9140, df=15  (Group-specific Yxx, common k & Tau's)
Reduced:      R2=0.9135, df=12  (Specific Y18,Y19,Y24. Common Y1,Y2,Y3, k, Tau,Tau2)
Significance: F(3,80)=0.1641, p=0.92027508

Plot the fit of the twelve-parameter model

clf
d = param12_problem.ydata ;
CI = [CI_medpr2 CI_mhdpr2] ;
f = param12_fit.yhat ;
train_easy_p = [true true false false] ; % Use to define easy and hard
circle_width_p = [false true false true] ; % Use to increase circle line width
for k = 1:4
    hold on ;  % must be inside the loop
    t = gT + JTR4(k) ;
    C = clr(k) ;      % color for this group. Always remains consistent
    s1 = sym1(k) ;    % transfer symbol for this group
    s2 = sym2(k) ;    % training symbol for this group
    h = plot(...
        t(i1)  ,d(i1,k) ,[C s1]   ... % 1: pre-test data
       ,t(i1)  ,f(i1,k) ,[C '-']  ... % 1: pre-test fit
       ,t(i2)  ,d(i2,k) ,[C s2]   ... % 2: train data
       ,t(i2)  ,f(i2,k) ,[C '-']  ... % 2: train fit
       ,t(i3)  ,d(i3,k) ,[C s1]   ... % 3: post-test data
       ,t(i3)  ,f(i3,k) ,[C '-']  ... % 3: post-test fit
       ) ;
    % Filled symbols demarkate groups training on first-order stimuli
    if (train_first_p(k))
        set(h,'MarkerFaceColor',C) ;
    %else  leave symbols open
    end
    % Large symbols demarkate easy delta
    if (train_easy_p(k))
        set(h,'Markersize',12) ;
    end
    % Increases line width for group 2 to make more visible
    if (circle_width_p(k))
        set(h,'LineWidth',1.1);
    end
    % Error bars w/in Ss.  (This call contains an implicit 'hold off')
    errorbar1(t,d(:,k),CI(:,k),[C 'n']) ;   % no whiskers
end
hold off ; box on ;
clear d CI h f

axis([0 N_trials 0 M]) ; grid on ;
set(gca,'xtick',xtick,'ytick',(0:.5:M)) ;
xlabel('Trial') ; ylabel('d''') ;
title(sprintf('MLSecond02: 12-param regression: R2=%.3f, RMSE=%.4f ' ...
     ,param12_fit.R2 ,param12_fit.RMSE ));

Eleven-parameter model: Common Y18

Intended to test the hypothesis that the learning during the training phase of the two groups are completely equivalent. That is, Y18 is also shared between the two groups, together with Y1, Y2, Y3, k, Tau, Tau2. Total number of params: 4+2*2+1+2=11

% Representation scheme: X is a 1x11 vector:
% x(1:4) stores [Y1 Y2 Y3 Y18] for both Hard groups
% x(5:6) stores [Y19 Y24] for HdGr1
% x(7:8) stores [Y19 Y24] for HdGr2
% x(9) stores k = EzYxx/HdYxx for both groups
% x(10) and x(11) store Tau and Tau2 for both groups
param11_vector_names = { ...
    'HdY1'     'HdY2'     'HdY3'   'HdY18'     ...   % 1:4
    'HdGr1Y19' 'HdGr1Y24'                      ...   % 5:6
    'HdGr2Y19' 'HdGr2Y24'                      ...   % 7:8
    'k'        'tau'      'tau2'     } ;             % 9:11

param11_vect2param = @(x) ...
    ([ x(9).*x(1:4) ...  % EzGr1: [Y1  Y2  Y3 Y18]
      ,x(9).*x(5:6) ...  % EzGr1: [Y19 Y24]
      ,x(10),x(11)  ...  % EzGr1: [Tau Tau2]
     ; x(9).*x(1:4) ...  % EzGr2: [Y1  Y2  Y3 Y18]
      ,x(9).*x(7:8) ...  % EzGr2: [Y19 Y24]
      ,x(10),x(11)  ...  % EzGr2: [Tau Tau2]
     ;       x(1:4) ...  % HdGr1: [Y1  Y2  Y3 Y18]
      ,      x(5:6) ...  % HdGr1: [Y19 Y24]
      ,x(10),x(11)  ...  % HdGr2: [Tau Tau2]
     ;       x(1:4) ...  % HdGr2: [Y1  Y2  Y3 Y18]
      ,      x(7:8) ...  % HdGr2: [Y19 Y24]
      ,x(10),x(11)  ]);  % HdGr2: [Tau Tau2]

param11_param2vect = @(p) ...
    ([p(3,1:4) ...    % [Y1  Y2 Y3 Y18] for both Hard groups
     ,p(3,5:6) ...    % [Y19 Y24] for HdGr1
     ,p(4,5:6) ...    % [Y19 Y24] for HdGr2
     ,geomean([geomean(p(1,1:6)./p(3,1:6))   ... % geomean([Gr1_k,Gr2_k])
              ,geomean(p(2,1:6)./p(4,1:6))]) ...
     ,p(1,7) p(1,8) ]) ;                         % Common Tau and Tau2

% Construct a new problem structure based on saturated_problem:
param11_problem = saturated_problem ;
param11_problem.comment = 'Specific Y19,Y24. Common Y1,Y2,Y3,Y18, k, Tau,Tau2' ;
param11_problem.vect2param = param11_vect2param ;
param11_problem.param2vect = param11_param2vect ;
param11_problem.vector_names = param11_vector_names ;

% Start the new search from param12_fit.opt_params:
x = param11_param2vect(param12_fit.opt_params) ;
param11_problem.x0 = x ;

p = param11_vect2param(x) ;
param11_problem.params0 = p ;
assert(all(x==param11_param2vect(p))) ;  % Sanity check

% Inherit the bounds from saturated_problem:
p = saturated_problem.vect2param(saturated_problem.lb_x) ;
x = param11_param2vect(p) ;
x(9) = 1.0 ;     % lower bound on k. This mandates that EzYxx>=HdYxxx
assert(max(max(abs(p-param11_vect2param(x))))<1e-6) ; % Sanity check
param11_problem.lb_x = x ;

p = saturated_problem.vect2param(saturated_problem.ub_x) ;
x = param11_param2vect(p) ;
assert(max(max(abs(p-param11_vect2param(x))))<1e-6) ; % Sanity check
x(9) = 2.0 ;     % upper bound on k
param11_problem.ub_x = x      %#ok<NOPTS>

% Optimization options. See optimset('lsqnonlin') for details
%param11_problem.options.Display = 'iter' ;  % verbose optimization
param11_problem = 

         comment: 'Specific Y19,Y24. Common Y1,Y2,Y3,Y18, k, Tau,Tau2'
           xdata: [1x1 struct]
           ydata: [24x4 double]
      vect2param: [function_handle]
      param2vect: [function_handle]
    vector_names: {'HdY1'  'HdY2'  'HdY3'  'HdY18'  'HdGr1Y19'  'HdGr1Y24'  'HdGr2Y19'  'HdGr2Y24'  'k'  'tau'  'tau2'}
              x0: [0.7762 1.0085 0.9316 1.4999 0.8653 1.2456 1.3326 1.3525 1.3508 1.5622e+03 140.1366]
         params0: [4x8 double]
            lb_x: [0 0 0 0 0 0 0 0 1 10 10]
            ub_x: [4 4 4 4 4 4 4 4 2 10000 10000]
         options: [1x1 struct]
       group_idx: [1x1 struct]

Fit the eleven-parameter model

param11_fit = MLZ02_lsqcurvefit(param11_problem)   %#ok<NOPTS>

fprintf('\nGroup:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 \n') ;
for k = 1:4
    p = param11_fit.opt_params(k,:) ;
    fprintf('%s: %5.2f %5.2f   %5.2f %5.2f   %5.2f %5.2f   %5d %5d \n' ...
           ,G.descr{k} ...
           ,p(I.Y1),p(I.Y2), p(I.Y3),p(I.Y18), p(I.Y19),p(I.Y24)   ...
           ,round(p(I.Tau)), round(p(I.Tau2)) ) ;
end
fprintf('EzYxx/HdYxx = k = %.4f \n\n',param11_fit.opt_x(9)) ;

% Test the transition param12_problem --> param11_problem
Mf = param12_fit ;         % full model
Mr = param11_fit ;         % reduced model
df_f = numel(Mf.opt_x) ;   % degrees of freedom (# params) full model
df_r = numel(Mr.opt_x) ;   % degrees of freedom (# params) reduced model
[F,p] = R2signif(N_data_points,Mf.R2,df_f,Mr.R2,df_r) ;
fprintf('Full:         R2=%.4f, df=%2d  (%s)\n',Mf.R2,df_f,Mf.comment) ;
fprintf('Reduced:      R2=%.4f, df=%2d  (%s)\n',Mr.R2,df_r,Mr.comment) ;
fprintf('Significance: F(%d,%d)=%.4f, p=%.8f\n\n' ...
       , df_f-df_r, N_data_points-df_f-1, F, p) ;

% Conclusion: The drop in R2 (.9135 --> .8928) is highly statistically
% significant and cannot be offset by 1 additional degree of freedom.
% It is useful to repeat this analysis taking into account that only the
% training segment of the curve constrains the param12-->param11 nesting.
% This affects the total degrees of freedom and hence the p value.
df_f = 5 ;   % Y3, Y18_1, Y18_2, k, Tau
df_r = 4 ;   % Y3, Y18, k, Tau
N_training_points = 4*16 ;   % blocks 3-18 inclusive
[F,p] = R2signif(N_training_points,Mf.R2,df_f,Mr.R2,df_r) ;
fprintf('Full:         R2=%.4f, df=%2d  (%s)\n',Mf.R2,df_f,Mf.comment) ;
fprintf('Reduced:      R2=%.4f, df=%2d  (%s)\n',Mr.R2,df_r,Mr.comment) ;
fprintf('Significance: F(%d,%d)=%.4f, p=%.8f\n' ...
       , df_f-df_r, N_training_points-df_f-1, F, p) ;

% Conclusion: Still highly significant. The eleven-parameter model must be
% rejected in favor of the twelve-parameter model.

% *** Overall conclusion: ***
% The twelve parameter model offers a better description of the data.
% Note:  This does *not* mean that there is more learning in Group 1 than
% in Group 2 because the present analysis ignores the within-group
% variability across participants.  It is based on within-block variability
% of the group-averaged profiles.  These data are not independent when
% group comparisons are concerned and, therefore, cannot be used to
% establish significant *differences* between the groups. See the section
%"z-test whether there is more learning in Group 1 than in Group 2" for a
% bootstrap test that points that in fact the two groups are not
% significantly different.  [AP 2010-01-21]
param11_fit = 

       comment: 'Specific Y19,Y24. Common Y1,Y2,Y3,Y18, k, Tau,Tau2'
         opt_x: [0.7762 1.0085 0.9285 1.4313 0.8654 1.2457 1.3327 1.3526 1.3506 1.4972e+03 140.1373]
    opt_params: [4x8 double]
          yhat: [24x4 double]
          RMSE: 0.1040
            R2: 0.8928
      exitflag: 3
        output: [1x1 struct]


Group:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 
EzGr1:  1.05  1.36    1.25  1.93    1.17  1.68    1497   140 
EzGr2:  1.05  1.36    1.25  1.93    1.80  1.83    1497   140 
HdGr1:  0.78  1.01    0.93  1.43    0.87  1.25    1497   140 
HdGr2:  0.78  1.01    0.93  1.43    1.33  1.35    1497   140 
EzYxx/HdYxx = k = 1.3506 

Full:         R2=0.9135, df=12  (Specific Y18,Y19,Y24. Common Y1,Y2,Y3, k, Tau,Tau2)
Reduced:      R2=0.8928, df=11  (Specific Y19,Y24. Common Y1,Y2,Y3,Y18, k, Tau,Tau2)
Significance: F(1,83)=19.8757, p=0.00002568

Full:         R2=0.9135, df= 5  (Specific Y18,Y19,Y24. Common Y1,Y2,Y3, k, Tau,Tau2)
Reduced:      R2=0.8928, df= 4  (Specific Y19,Y24. Common Y1,Y2,Y3,Y18, k, Tau,Tau2)
Significance: F(1,58)=13.8890, p=0.00044181

New Eleven-parameter model: HdGr2Y19==HdGr2Y24

Test a model in which the post-test beginning (Y19) and end (Y24) are common in Group 2 but are allowed to vary independently in Group 1.

Representation scheme: X is a 1x11 vector: x(1:3) stores [Y1 Y2 Y3] for both Hard groups x(4:6) stores [Y18 Y19 Y24] for HdGr1 x(7) stores [Y18] for HdGr2 x(8) stores [Y19==24] for HdGr2 x(9) stores k = EzYxx/HdYxx for both groups x(10) and x(11) store Tau and Tau2 for both groups

param11n_vector_names = { ...
    'HdY1'     'HdY2'     'HdY3'     ...   % 1:3
    'HdGr1Y18' 'HdGr1Y19' 'HdGr1Y24' ...   % 4:6
    'HdGr2Y18' 'HdGr2Y19'  ...             % 7:8
    'k'        'tau'      'tau2'     } ;   % 9:11
param11n_K_idx = 9 ;

param11n_vect2param = @(x) ...
    ([ x(9).*x(1:3) ...   % EzGr1: [Y1  Y2  Y3 ]
      ,x(9).*x(4:6) ...   % EzGr1: [Y18 Y19 Y24]
      ,x(10), x(11)  ...  % EzGr1: [Tau Tau2]
                    ...
     ; x(9).*x(1:3) ...   % EzGr2: [Y1  Y2  Y3 ]
      ,x(9).*x(7:8) ...   % EzGr2: [Y18 Y19]
      ,x(9).*x(8)   ...   % EzGr2: Y24==Y19
      ,x(10), x(11)  ...  % EzGr2: [Tau Tau2]
                     ...
     ;        x(1:3) ...  % HdGr1: [Y1  Y2  Y3 ]
      ,       x(4:6) ...  % HdGr1: [Y18 Y19 Y24]
      ,x(10), x(11)  ...  % HdGr1: [Tau Tau2]
                     ...
     ;        x(1:3) ...  % HdGr2: [Y1  Y2  Y3 ]
      ,       x(7:8) ...  % HdGr2: [Y18 Y19]
      ,       x(8)   ...  % HdGr2: Y24==Y19
      ,x(10), x(11)  ]);  % HdGr2: [Tau Tau2]

param11n_param2vect = @(p) ...
     ([p(3,1:3) ...    % [Y1  Y2  Y3] for both Hard groups
      ,p(3,4:6) ...    % [Y18 Y19 24] for HdGr1
      ,p(4,4:5) ...    % [Y18 Y19]    for HdGr2
      ,geomean([geomean(p(1,1:6)./p(3,1:6))   ... % geomean([Gr1_k,Gr2_k])
               ,geomean(p(2,1:6)./p(4,1:6))]) ...
      ,p(1,7) p(1,8) ]) ;                         % Common Tau and Tau2


% Construct a new problem structure based on saturated_problem:
param11n_problem = saturated_problem ;
param11n_problem.comment = 'Gr1: Y18,Y19,Y24; Gr2: Y18,Y19==Y24. Common Y1,Y2,Y3, k, Tau,Tau2' ;
param11n_problem.vect2param = param11n_vect2param ;
param11n_problem.param2vect = param11n_param2vect ;
param11n_problem.vector_names = param11n_vector_names ;

% Start the new search from saturY_cmnTau_fit.opt_params:
x = param11n_param2vect(param12_fit.opt_params) ;
param11n_problem.x0 = x ;

p = param11n_vect2param(x) ;
param11n_problem.params0 = p ;
assert(all(x==param11n_param2vect(p))) ;  % Sanity check

% Inherit the bounds from saturated_problem:
p = saturated_problem.vect2param(saturated_problem.lb_x) ;  % canonicalize
x = param11n_param2vect(p) ;
x(param11n_K_idx) = 1.0 ;     % lower bound on k. This mandates that EzYxx>=HdYxxx
assert(max(max(abs(p-param11n_vect2param(x))))<1e-6) ; % Sanity check
param11n_problem.lb_x = x ;

p = saturated_problem.vect2param(saturated_problem.ub_x) ;  % canonicalize
x = param11n_param2vect(p) ;
assert(max(max(abs(p-param11n_vect2param(x))))<1e-6) ; % Sanity check
x(param11n_K_idx) = 2.0 ;     % upper bound on k
param11n_problem.ub_x = x      %#ok<NOPTS>

% Optimization options. See optimset('lsqnonlin') for details
%param12_problem.options.Display = 'iter' ;  % verbose optimization
param11n_problem = 

         comment: 'Gr1: Y18,Y19,Y24; Gr2: Y18,Y19==Y24. Common Y1,Y2,Y3, k, Tau,Tau2'
           xdata: [1x1 struct]
           ydata: [24x4 double]
      vect2param: [function_handle]
      param2vect: [function_handle]
    vector_names: {1x11 cell}
              x0: [0.7762 1.0085 0.9316 1.4999 0.8653 1.2456 1.3677 1.3326 1.3508 1.5622e+03 140.1366]
         params0: [4x8 double]
            lb_x: [0 0 0 0 0 0 0 0 1 10 10]
            ub_x: [4 4 4 4 4 4 4 4 2 10000 10000]
         options: [1x1 struct]
       group_idx: [1x1 struct]

Fit the New Eleven-parameter model (HdGr2Y19==HdGr2Y24)

param11n_fit = MLZ02_lsqcurvefit(param11n_problem)   %#ok<NOPTS>

fprintf('\nGroup:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 \n') ;
for k = 1:4
    p = param11n_fit.opt_params(k,:) ;
    fprintf('%s: %5.2f %5.2f   %5.2f %5.2f   %5.2f %5.2f   %5d %5d \n' ...
           ,G.descr{k} ...
           ,p(I.Y1),p(I.Y2), p(I.Y3),p(I.Y18), p(I.Y19),p(I.Y24)   ...
           ,round(p(I.Tau)), round(p(I.Tau2)) ) ;
end
fprintf('EzYxx/HdYxx = k = %.4f \n\n',param11n_fit.opt_x(param11n_K_idx)) ;

% Test the transition indepGr_cmnKTau_problem --> param12_problem
Mf = param12_fit ;         % full model
Mr = param11n_fit ;         % reduced model
df_f = numel(Mf.opt_x) ;   % degrees of freedom (# params) full model
df_r = numel(Mr.opt_x) ;   % degrees of freedom (# params) reduced model
[F,p] = R2signif(N_data_points,Mf.R2,df_f,Mr.R2,df_r) ;
fprintf('Full:         R2=%.4f, df=%2d  (%s)\n',Mf.R2,df_f,Mf.comment) ;
fprintf('Reduced:      R2=%.4f, df=%2d  (%s)\n',Mr.R2,df_r,Mr.comment) ;
fprintf('Significance: F(%d,%d)=%.4f, p=%.8f\n' ...
       , df_f-df_r, N_data_points-df_f-1, F, p) ;

% Conclusion: The drop in R2 (.9135 --> .9134) is not statistically
% so the New Eleven parameter model seems to be our final model rather
% than the twelve-parameter model.
param11n_fit = 

       comment: 'Gr1: Y18,Y19,Y24; Gr2: Y18,Y19==Y24. Common Y1,Y2,Y3, k, Tau,Tau2'
         opt_x: [0.7762 1.0084 0.9316 1.4999 0.8649 1.2449 1.3677 1.3482 1.3508 1.5622e+03 137.5419]
    opt_params: [4x8 double]
          yhat: [24x4 double]
          RMSE: 0.0935
            R2: 0.9134
      exitflag: 3
        output: [1x1 struct]


Group:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 
EzGr1:  1.05  1.36    1.26  2.03    1.17  1.68    1562   138 
EzGr2:  1.05  1.36    1.26  1.85    1.82  1.82    1562   138 
HdGr1:  0.78  1.01    0.93  1.50    0.86  1.24    1562   138 
HdGr2:  0.78  1.01    0.93  1.37    1.35  1.35    1562   138 
EzYxx/HdYxx = k = 1.3508 

Full:         R2=0.9135, df=12  (Specific Y18,Y19,Y24. Common Y1,Y2,Y3, k, Tau,Tau2)
Reduced:      R2=0.9134, df=11  (Gr1: Y18,Y19,Y24; Gr2: Y18,Y19==Y24. Common Y1,Y2,Y3, k, Tau,Tau2)
Significance: F(1,83)=0.0849, p=0.77143834

Plot the fit of the New Eleven-parameter model

clf
d = param11n_problem.ydata ;
CI = [CI_medpr2 CI_mhdpr2] ;
f = param11n_fit.yhat ;
train_easy_p = [true true false false] ; % Use to define easy and hard
circle_width_p = [false true false true] ; % Use to increase circle line width
for k = 1:4
    hold on ;  % must be inside the loop
    t = gT + JTR4(k) ;
    C = clr(k) ;      % color for this group. Always remains consistent
    s1 = sym1(k) ;    % transfer symbol for this group
    s2 = sym2(k) ;    % training symbol for this group
    h = plot(...
        t(i1)  ,d(i1,k) ,[C s1]   ... % 1: pre-test data
       ,t(i1)  ,f(i1,k) ,[C '-']  ... % 1: pre-test fit
       ,t(i2)  ,d(i2,k) ,[C s2]   ... % 2: train data
       ,t(i2)  ,f(i2,k) ,[C '-']  ... % 2: train fit
       ,t(i3)  ,d(i3,k) ,[C s1]   ... % 3: post-test data
       ,t(i3)  ,f(i3,k) ,[C '-']  ... % 3: post-test fit
       ) ;
    % Filled symbols demarkate groups training on first-order stimuli
    if (train_first_p(k))
        set(h,'MarkerFaceColor',C) ;
    %else  leave symbols open
    end
    % Large symbols demarkate easy delta
    if (train_easy_p(k))
        set(h,'Markersize',12) ;
    end
    % Increases line width for group 2 to make more visible
    if (circle_width_p(k))
        set(h,'LineWidth',1.1);
    end
    % Error bars w/in Ss.  (This call contains an implicit 'hold off')
    errorbar1(t,d(:,k),CI(:,k),[C 'n']) ;   % no whiskers
end
hold off ; box on ;
clear d CI h f

axis([0 N_trials 0 M]) ; grid on ;
set(gca,'xtick',xtick,'ytick',(0:.5:M)) ;
xlabel('Trial') ; ylabel('d''') ;
title(sprintf('MLSecond02: New 11-param regression: R2=%.3f, RMSE=%.4f ' ...
     ,param11n_fit.R2 ,param11n_fit.RMSE ));

Define two specificity indices

Following Ahissar & Hochstein (199?), the specificity index can be defined by the switch cost divided by the total learning effect:

SI1 = (Y18 - Y19) / (Y18 - Y1)

This is calculated separately for each group and difficulty level. (The difficulty cancels out because of the proportionality.)

The above index assumes the two conditions are equivalent. This assumption is violated in our experiment because the final (Y18) level on first-order stimuli is greater than that on second-order stim. This motivates an alternative definition for the specificity index:

SI2 = (Y18other - Y19) / (Y18other - Y1)

In this formula, Y18other stands for the final level in the other group. The second index has the advantage that all 3 datums are collected with identical stimuli. The disadvantage is that it mixes data b/n sbj groups.

Both indices are implemented below. They take as input the full 4x8 parameter matrix and return a 4x1 vector of specificity indices.

specif_idx1 = @(p) ((p(:,4)-p(:,5)) ./ (p(:,4)-p(:,1))) ;  %(Y18-Y19)/(Y18-Y1)

specif_idx2 = @(p) ...
    ([(p(2,4)-p(1,5)) ./ (p(2,4)-p(1,1)) ...   % Easy second-order stim
     ;(p(1,4)-p(2,5)) ./ (p(1,4)-p(2,1)) ...   % Easy first-order stim
     ;(p(4,4)-p(3,5)) ./ (p(4,4)-p(3,1)) ...   % Hard second-order stim
     ;(p(3,4)-p(4,5)) ./ (p(3,4)-p(4,1)) ]) ;  % Hard first-order stim

Compute both specificity indices for all regression fits

raw_SI1 = specif_idx1(main_params0)' ;  % main_params0 are the raw data
raw_SI2 = specif_idx2(main_params0)' ;  % main_params0 are the raw data
fprintf('\nRaw data:        SI1=%s  SI2=%s\n' ...
       ,mat2str(raw_SI1,3),mat2str(raw_SI2,3)) ;

p = saturated_fit.opt_params ;
saturated_fit.specif_idx1 = specif_idx1(p)' ;
saturated_fit.specif_idx2 = specif_idx2(p)' ;
fprintf('Saturated model: SI1=%s   SI2=%s\n' ...
       ,mat2str(saturated_fit.specif_idx1,3) ...
       ,mat2str(saturated_fit.specif_idx2,3)) ;

p = saturY_cmnTau_fit.opt_params ;
saturY_cmnTau_fit.specif_idx1 = specif_idx1(p)' ;
saturY_cmnTau_fit.specif_idx2 = specif_idx2(p)' ;
fprintf('Common tau''s:    SI1=%s SI2=%s\n' ...
       ,mat2str(saturY_cmnTau_fit.specif_idx1,3) ...
       ,mat2str(saturY_cmnTau_fit.specif_idx2,3)) ;

p = indepGr_cmnKTau_fit.opt_params ;
indepGr_cmnKTau_fit.specif_idx1 = specif_idx1(p)' ;
indepGr_cmnKTau_fit.specif_idx2 = specif_idx2(p)' ;
fprintf('Easy = k*Hard:   SI1=%s  SI2=%s\n' ...
       ,mat2str(indepGr_cmnKTau_fit.specif_idx1,3) ...
       ,mat2str(indepGr_cmnKTau_fit.specif_idx2,3)) ;

p = param12_fit.opt_params ;
param12_fit.specif_idx1 = specif_idx1(p)' ;
param12_fit.specif_idx2 = specif_idx2(p)' ;
fprintf('12-param model:  SI1=%s  SI2=%s\n' ...
       ,mat2str(param12_fit.specif_idx1,3) ...
       ,mat2str(param12_fit.specif_idx2,3)) ;

p = param11n_fit.opt_params ;
param11n_fit.specif_idx1 = specif_idx1(p)' ;
param11n_fit.specif_idx2 = specif_idx2(p)' ;
fprintf('New 11-param m:  SI1=%s  SI2=%s\n' ...
       ,mat2str(param11n_fit.specif_idx1,3) ...
       ,mat2str(param11n_fit.specif_idx2,3)) ;
Raw data:        SI1=[0.813 -0.0377 0.912 0.146]  SI2=[0.789 0.0937 0.886 0.343]
Saturated model: SI1=[0.828 -0.0949 0.906 0.19]   SI2=[0.78 0.163 0.872 0.407]
Common tau's:    SI1=[0.825 -0.00854 0.917 0.197] SI2=[0.788 0.182 0.898 0.35]
Easy = k*Hard:   SI1=[0.856 0.0601 0.856 0.0601]  SI2=[0.824 0.238 0.824 0.238]
12-param model:  SI1=[0.877 0.0593 0.877 0.0593]  SI2=[0.849 0.231 0.849 0.231]
New 11-param m:  SI1=[0.877 0.0328 0.877 0.0328]  SI2=[0.85 0.21 0.85 0.21]

Prepare to run MLZ02_dprfit_bootstrap

Call MLZ02_dprfit_bootstrap to generate a "standard job descriptor". It requests 1000 bootstrap samples and fits two models to each: * main model is the 12-parameter model above (param12_problem) * alt model is the 15-parameter model indepGr_cmnKTau_problem

Note that MLZ02_dprfit_bootstrap() needs to load H_adjusted.mat generated and saved as H_adjusted_filename above.

job = MLZ02_dprfit_bootstrap ;

N_samples = 1000 ;
job.N_samples = N_samples    %#ok<NOPTS>
MLZ02_dprfit_bootstrap(): Generating standard job from scratch:
load /Users/apetrov/a/r/w/work/MLExper/MLSecond02/data/H_adjusted.mat 

   Value   Count  Percent  Cum_cnt  Cum_pct
-------------------------------------------
      13      10    50.00       10    50.00
      24      10    50.00       20   100.00
-------------------------------------------


problem = 

         comment: 'Gr1: Y18,Y19,Y24; Gr2: Y18,Y19==Y24. Common Y1,Y2,Y3, k, Tau,Tau2'
           xdata: [1x1 struct]
           ydata: []
      vect2param: [function_handle]
      param2vect: [function_handle]
    vector_names: {1x11 cell}
              x0: [0.8000 1 0.9000 1.5000 0.9000 1.2000 1.4000 1.3000 1.3500 1500 140]
         params0: [4x8 double]
            lb_x: [0 0 0 0 0 0 0 0 1 100 10]
            ub_x: [4 4 4 4 4 4 4 4 3 9999 999]
         options: [1x1 struct]
       group_idx: [1x1 struct]


problem_alt = 

         comment: 'Group-specific Yxx. Common k, Tau, Tau2'
           xdata: [1x1 struct]
           ydata: []
      vect2param: [1x1 function_handle]
      param2vect: [function_handle]
    vector_names: {1x15 cell}
              x0: [0.8000 1 0.9000 1.5000 0.9000 1.2000 0.8000 1 0.9000 1.4000 1.3000 1.3000 1.3500 1500 140]
         params0: [4x8 double]
            lb_x: [0 0 0 0 0 0 0 0 0 0 0 0 1 100 10]
            ub_x: [4 4 4 4 4 4 4 4 4 4 4 4 3 9999 999]
         options: [1x1 struct]
       group_idx: [1x1 struct]


job = 

        comment: 'Standard MLZ02_dprfit_bootstrap job'
          edpr2: [24x20 double]
          hdpr2: [24x20 double]
          group: [24 13 13 13 24 24 24 13 13 13 13 24 13 24 24 24 13 13 24 24]
    group_descr: {'TrainFirst'  'TrainSecond'}
      N_samples: 1000
        problem: [1x1 struct]
    problem_alt: [1x1 struct]
    specif_idx1: @(p)((p(:,4)-p(:,5))./(p(:,4)-p(:,1)))
    specif_idx2: [function_handle]

Calculate bootstrap samples

B_filename = fullfile(MLSecond02_pathstr,'data',sprintf('B%d.mat',N_samples)) ;
if (exist(B_filename,'file'))
    fprintf('load %s \n',B_filename) ;
    load(B_filename) ;
    assert(numel(B.R2)==N_samples+1) ;
else  % must calculate it here, which takes 6 minutes on Vega for 1000 samples
    B = MLZ02_dprfit_bootstrap(job) ;
    fprintf('save %s \n\n',B_filename) ;
    save(B_filename,'B') ;
end

%- Verify the convergence of the search algorithm
%  Exit flags >=1 are OK. <0 are bad. See 'doc lsqnonlin' for details
xtab1(B.exitflag) ;
xtab1(B.exitflag_alt) ;
load /Users/apetrov/a/r/w/work/MLExper/MLSecond02/data/B1000.mat 

   Value   Count  Percent  Cum_cnt  Cum_pct
-------------------------------------------
       1      45     4.50       45     4.50
       3     956    95.50     1001   100.00
-------------------------------------------


   Value   Count  Percent  Cum_cnt  Cum_pct
-------------------------------------------
       1      17     1.70       17     1.70
       3     984    98.30     1001   100.00
-------------------------------------------

The first "sample" is always the full data set:

SUPERSEDED: % The main fit should be the 12-parameter fit SUPERSEDED: err = B.optX(1,:)-param12_fit.opt_x ; SUPERSEDED: err(11:12) = err(11:12)./1000 ; % tau & tau2

% The main fit should be the New 11-parameter fit
err = B.optX(1,:)-param11n_fit.opt_x ;
err(10:11) = err(10:11)./1000 ;     % tau & tau2
assert(max(abs(err))<1e-3) ;

% The alternative fit should be the indepGr_cmnKTau_fit
err = B.optX_alt(1,:)-indepGr_cmnKTau_fit.opt_x ;
err(11:12) = err(11:12)./1000 ;     % tau & tau2
assert(max(abs(err))<1e-3) ;

Explore the New 11-parameter model performance

fprintf('Main model: R2=%.4f  RMSE=%.4f\n',B.R2(1),B.RMSE(1)) ;
describe([B.R2(2:end) B.RMSE(2:end)]) ;
Main model: R2=0.9134  RMSE=0.0935

    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   0.845    0.035      0.69    0.82    0.85    0.87    0.93
   0.136    0.017      0.10    0.12    0.13    0.15    0.23
------------------------------------------------------------
   0.490    0.026      0.39    0.47    0.49    0.51    0.58

Explore the parameters of the New 11-parameter model

x = B.optX(1,:) ;
par = job.problem.vect2param(x) ;
fprintf('\nGroup:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 \n') ;
for k = 1:4
    p = par(k,:) ;
    fprintf('%s: %5.2f %5.2f   %5.2f %5.2f   %5.2f %5.2f   %5d %5d \n' ...
           ,G.descr{k} ...
           ,p(I.Y1),p(I.Y2), p(I.Y3),p(I.Y18), p(I.Y19),p(I.Y24)   ...
           ,round(p(I.Tau)), round(p(I.Tau2)) ) ;
end
fprintf('EzYxx/HdYxx = k = %.4f \n',x(param11n_K_idx)) ;

describe(B.optX(2:end,:)) ;

C = corrcoef(B.optX(2:end,:)) ;
vn = job.problem.vector_names ;
fprintf('\nCross-correlation matrix of parameters:') ;
for k=1:size(C,1)
    fprintf('\n%8s:',vn{k}) ;
    fprintf(' %5.2f',C(k,:)) ;
end
fprintf('\n\n') ;
Group:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 
EzGr1:  1.05  1.36    1.26  2.03    1.17  1.68    1562   138 
EzGr2:  1.05  1.36    1.26  1.85    1.82  1.82    1562   138 
HdGr1:  0.78  1.01    0.93  1.50    0.86  1.24    1562   138 
HdGr2:  0.78  1.01    0.93  1.37    1.35  1.35    1562   138 
EzYxx/HdYxx = k = 1.3508 

    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   0.778    0.097      0.45    0.71    0.78    0.85    1.11
   1.010    0.075      0.80    0.96    1.01    1.06    1.26
   0.924    0.070      0.74    0.88    0.92    0.97    1.14
   1.502    0.189      0.86    1.38    1.50    1.63    2.08
   0.868    0.098      0.58    0.80    0.87    0.94    1.21
   1.250    0.096      0.87    1.19    1.25    1.31    1.53
   1.359    0.120      1.01    1.28    1.36    1.44    1.68
   1.348    0.128      1.01    1.26    1.35    1.43    1.71
   1.351    0.019      1.29    1.34    1.35    1.36    1.41
1522.994  607.739    440.49 1111.98 1430.32 1799.39 5626.80
 129.895   65.075     10.00   91.84  134.25  172.78  442.26
------------------------------------------------------------
 151.207   61.246     41.65  110.33  143.18  180.29  552.93

Cross-correlation matrix of parameters:
    HdY1:  1.00  0.75  0.65  0.17  0.28  0.20  0.43  0.49 -0.01 -0.20  0.00
    HdY2:  0.75  1.00  0.74  0.11  0.28  0.17  0.69  0.69  0.03 -0.20 -0.23
    HdY3:  0.65  0.74  1.00  0.37  0.36  0.34  0.70  0.58 -0.19  0.13 -0.04
HdGr1Y18:  0.17  0.11  0.37  1.00  0.40  0.89  0.00 -0.05 -0.22  0.43  0.12
HdGr1Y19:  0.28  0.28  0.36  0.40  1.00  0.31 -0.06 -0.01  0.32  0.08 -0.20
HdGr1Y24:  0.20  0.17  0.34  0.89  0.31  1.00  0.12  0.04 -0.20  0.43  0.35
HdGr2Y18:  0.43  0.69  0.70  0.00 -0.06  0.12  1.00  0.71 -0.18  0.06  0.12
HdGr2Y19:  0.49  0.69  0.58 -0.05 -0.01  0.04  0.71  1.00 -0.24 -0.17 -0.01
       k: -0.01  0.03 -0.19 -0.22  0.32 -0.20 -0.18 -0.24  1.00 -0.15 -0.17
     tau: -0.20 -0.20  0.13  0.43  0.08  0.43  0.06 -0.17 -0.15  1.00  0.38
    tau2:  0.00 -0.23 -0.04  0.12 -0.20  0.35  0.12 -0.01 -0.17  0.38  1.00

z-test for the learning effect

Construct the difference (Y18-Y3) and show that it is greater than zero.

Representation scheme for "New 11-parameter model": X is a 1x11 vector: x(1:3) stores [Y1 Y2 Y3] for both Hard groups x(4:6) stores [Y18 Y19 Y24] for HdGr1 x(7) stores [Y18] for HdGr2

d = B.optX(2:end,[3 4 7]) ;            % [Y3 Y18_HdGr1 Y18_HdGr2]
d = [d , d(:,2)-d(:,1), d(:,3)-d(:,1)] ;   % [Y3 Y18_1 Y18_2, learn_1, learn_2]
describe(d) ;

% par(3,:) has 8 params for HdGr1; par(4,:) for HdGr2
learn_mn = [par(3,I.Y18)-par(3,I.Y3) par(4,I.Y18)-par(4,I.Y3)]
learn_sd = std(d(:,[4 5]),1)      %#ok<NOPTS>  % bootstrap std.dev
learn_CI90 = sqrt(mean(learn_sd.^2)) .* z_crit
learn_CI90 = [learn_mn-learn_CI90 ; learn_mn+learn_CI90]
learn_z = learn_mn./learn_sd
1-normcdf(learn_z)                %#ok<MNEFF>

% Conclusion: The statistics confirm the obvious. There is learning in both
% groups.  None of the 2*1000 samples shows negative learning effects.
    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   0.924    0.070      0.74    0.88    0.92    0.97    1.14
   1.502    0.189      0.86    1.38    1.50    1.63    2.08
   1.359    0.120      1.01    1.28    1.36    1.44    1.68
   0.578    0.176      0.06    0.46    0.57    0.69    1.15
   0.435    0.086      0.19    0.37    0.43    0.49    0.70
------------------------------------------------------------
   0.960    0.128      0.57    0.87    0.96    1.05    1.35

learn_mn =

    0.5682    0.4360


learn_sd =

    0.1755    0.0863


learn_CI90 =

    0.2275


learn_CI90 =

    0.3408    0.2086
    0.7957    0.6635


learn_z =

    3.2381    5.0522


ans =

   1.0e-03 *

    0.6017    0.0002

z-test whether there is more learning in Group 1 than in Group 2

d = [d, d(:,4)-d(:,5)] ;   % [Y3 Y18_1 Y18_2 learn_1 learn_2, diff_1_2]
describe(d) ;

learn_diff = par(3,I.Y18) - par(4,I.Y18)   %#ok<NOPTS> % HdGr1 - HdGr2
learn_diff_sd = [std(d(:,6)) sqrt(sum(std(d(:,[2 3])).^2))]
learn_diff_CI90 = learn_diff_sd(1) .* z_crit
learn_diff_CI90 = [learn_diff-learn_diff_CI90 ; learn_diff+learn_diff_CI90]
learn_diff_z = learn_diff/learn_diff_sd(1)
1-normcdf(learn_diff_z)         %#ok<MNEFF>

% Conclusion: Despite the appearance of the plot above, Y18 is *not*
% significantly different between the two groups.  The blue profile is
% systematically below the red profile across blocks 3-18, but these points
% are *not* independent.  Bootstrap re-sampling of subjects reveal that the
% .13 difference between Y18_1 and Y18_2 is not significant given the
% individual-subject variability.
%
% This does not cast doubt on our hierarchical-regression results above
% because there the conclusion was that differences were *not* significant
% and hence the number of free parameters can be reduced.  This is
% legitimate (or at least Alex thinks so).  Assertions of significant
% *differences* between groups are illegitimate. Once the individuals are
% averaged into groups, we effectively have only one observation (= group
% mean) per group.
    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   0.924    0.070      0.74    0.88    0.92    0.97    1.14
   1.502    0.189      0.86    1.38    1.50    1.63    2.08
   1.359    0.120      1.01    1.28    1.36    1.44    1.68
   0.578    0.176      0.06    0.46    0.57    0.69    1.15
   0.435    0.086      0.19    0.37    0.43    0.49    0.70
   0.143    0.224     -0.51   -0.01    0.15    0.30    0.94
------------------------------------------------------------
   0.823    0.144      0.39    0.73    0.82    0.92    1.28

learn_diff =

    0.1322


learn_diff_sd =

    0.2236    0.2237


learn_diff_CI90 =

    0.3677


learn_diff_CI90 =

   -0.2355
    0.4999


learn_diff_z =

    0.5914


ans =

    0.2771

z-test whether Y24 < Y18 in Group 1

Construct the difference (Y24-Y18) and test whether it is greater than zero.

Representation scheme for "New 11-parameter model": X is a 1x11 vector: x(4:6) stores [Y18 Y19 Y24] for HdGr1 x(7) stores [Y18] for HdGr2 x(8) stores [Y19==24] for HdGr2

d = B.optX(2:end,[4 6, 7 8]) ;     % [Y18_HdGr1 Y24_HdGr1, Y18_HdGr2 Y19_HdGr2]
d = [d , d(:,1)-d(:,2), d(:,3)-d(:,4)] ;  % [Y18_1 Y24_1 Y18_2 Y19_2, delta1 delta2]
describe(d) ;

post_diff = [par(3,I.Y18)-par(3,I.Y24), par(4,I.Y18)-par(4,I.Y19)]
post_diff_sd = std(d(:,5:6))
post_diff_CI90 = post_diff_sd .* z_crit
post_diff_CI90 = [post_diff-post_diff_CI90 ; post_diff+post_diff_CI90]
post_diff_z = post_diff./post_diff_sd
1-normcdf(post_diff_z) %#ok<MNEFF>
    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   1.502    0.189      0.86    1.38    1.50    1.63    2.08
   1.250    0.096      0.87    1.19    1.25    1.31    1.53
   1.359    0.120      1.01    1.28    1.36    1.44    1.68
   1.348    0.128      1.01    1.26    1.35    1.43    1.71
   0.252    0.112     -0.08    0.18    0.25    0.33    0.57
   0.011    0.095     -0.28   -0.05    0.01    0.08    0.27
------------------------------------------------------------
   0.954    0.123      0.57    0.87    0.96    1.04    1.31

post_diff =

    0.2550    0.0194


post_diff_sd =

    0.1120    0.0951


post_diff_CI90 =

    0.1842    0.1565


post_diff_CI90 =

    0.0708   -0.1370
    0.4391    0.1759


post_diff_z =

    2.2775    0.2042


ans =

    0.0114    0.4191

Descriptive statistics about the tau1-to-tau2 ratio

Take log of the time constants so that ratios become differences:

Representation scheme for "New 11-parameter model": X is a 1x11 vector: x(10) and x(11) store Tau and Tau2 for both groups

log_tau = log(B.optX(2:end,10:11)) ;             % [log_tau log_tau2]
log_tau = [log_tau, log_tau(:,1)-log_tau(:,2)] ; % [log_tau log_tau2, log_ratio]
describe(log_tau) ;
hist(log_tau(:,3),50) ; xlabel('log( tau / tau2 )') ;
st = exp(describe(log_tau))   % [mean std  min Q25 median Q75 max]

prctile(exp(log_tau(:,3)),[5 10 50 90 95])
    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   7.258    0.375      6.09    7.01    7.27    7.50    8.64
   4.616    0.896      2.30    4.52    4.90    5.15    6.09
   2.642    0.858      0.78    2.18    2.40    2.76    5.90
------------------------------------------------------------
   4.839    0.710      3.06    4.57    4.86    5.14    6.88

st =

   1.0e+03 *

    1.4191    0.0015    0.4405    1.1120    1.4303    1.7994    5.6268
    0.1010    0.0025    0.0100    0.0918    0.1343    0.1728    0.4423
    0.0140    0.0024    0.0022    0.0088    0.0110    0.0158    0.3650


ans =

    5.5624    6.9321   11.0483   71.3121  121.7748

Explore 15-parameter model performance

fprintf('Alternative model: R2=%.4f  RMSE=%.4f\n',B.R2_alt(1),B.RMSE_alt(1)) ;
describe([B.R2_alt(2:end) B.RMSE_alt(2:end)]) ;
Alternative model: R2=0.9140  RMSE=0.0931

    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   0.860    0.030      0.75    0.84    0.86    0.88    0.94
   0.129    0.014      0.10    0.12    0.13    0.14    0.19
------------------------------------------------------------
   0.495    0.022      0.42    0.48    0.50    0.51    0.56

Explore the parameters of the 15-parameter model

x = B.optX_alt(1,:) ;
par = job.problem_alt.vect2param(x) ;
fprintf('\nGroup:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 \n') ;
for k = 1:4
    p = par(k,:) ;
    fprintf('%s: %5.2f %5.2f   %5.2f %5.2f   %5.2f %5.2f   %5d %5d \n' ...
           ,G.descr{k} ...
           ,p(I.Y1),p(I.Y2), p(I.Y3),p(I.Y18), p(I.Y19),p(I.Y24)   ...
           ,round(p(I.Tau)), round(p(I.Tau2)) ) ;
end
fprintf('EzYxx/HdYxx = k = %.4f \n',x(indepGr_K_idx)) ;

describe(B.optX_alt(2:end,:)) ;

C = corrcoef(B.optX_alt(2:end,:)) ;
vn = job.problem_alt.vector_names ;
fprintf('\nCross-correlation matrix of parameters:') ;
for k=1:size(C,1)
    fprintf('\n%8s:',vn{k}) ;
    fprintf(' %5.2f',C(k,:)) ;
end
fprintf('\n\n') ;
Group:    Y1    Y2      Y3   Y18     Y19   Y24     Tau  Tau2 
EzGr1:  1.02  1.33    1.26  2.03    1.17  1.68    1561   140 
EzGr2:  1.07  1.39    1.26  1.85    1.80  1.83    1561   140 
HdGr1:  0.76  0.98    0.93  1.50    0.87  1.25    1561   140 
HdGr2:  0.79  1.03    0.93  1.37    1.33  1.35    1561   140 
EzYxx/HdYxx = k = 1.3507 

    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   0.757    0.112      0.34    0.68    0.76    0.84    1.02
   0.987    0.063      0.78    0.94    0.99    1.03    1.20
   0.933    0.074      0.72    0.88    0.93    0.98    1.18
   1.509    0.186      0.87    1.39    1.51    1.64    2.10
   0.869    0.099      0.58    0.80    0.87    0.94    1.21
   1.251    0.096      0.87    1.19    1.25    1.31    1.52
   0.798    0.158      0.35    0.68    0.79    0.91    1.28
   1.033    0.137      0.66    0.93    1.03    1.12    1.50
   0.931    0.118      0.61    0.85    0.92    1.01    1.30
   1.365    0.106      1.06    1.29    1.36    1.44    1.66
   1.334    0.115      0.97    1.26    1.33    1.41    1.73
   1.354    0.137      1.00    1.26    1.35    1.44    1.73
   1.351    0.019      1.29    1.34    1.35    1.36    1.41
1685.414  639.776    430.51 1261.31 1581.79 1992.37 6017.22
 137.129   71.048     10.00   98.11  140.39  179.40  541.31
------------------------------------------------------------
 122.468   47.483     30.04   91.53  115.78  145.81  438.49

Cross-correlation matrix of parameters:
 HdGr1Y1:  1.00  0.38  0.37  0.34  0.46  0.30  0.01 -0.02 -0.04 -0.04 -0.01  0.01 -0.06 -0.17  0.03
 HdGr1Y2:  0.38  1.00  0.44  0.41  0.68  0.35  0.00 -0.01 -0.00 -0.02  0.03  0.02  0.14 -0.05 -0.48
 HdGr1Y3:  0.37  0.44  1.00  0.58  0.65  0.37 -0.02 -0.06 -0.03 -0.04 -0.03 -0.08 -0.14  0.11 -0.22
HdGr1Y18:  0.34  0.41  0.58  1.00  0.39  0.90  0.01 -0.01  0.11  0.09  0.01  0.00 -0.23  0.41  0.10
HdGr1Y19:  0.46  0.68  0.65  0.39  1.00  0.31  0.02  0.00  0.04 -0.01 -0.01  0.00  0.31  0.13 -0.12
HdGr1Y24:  0.30  0.35  0.37  0.90  0.31  1.00  0.05  0.05  0.16  0.15  0.00  0.06 -0.21  0.40  0.33
 HdGr2Y1:  0.01  0.00 -0.02  0.01  0.02  0.05  1.00  0.90  0.81  0.53  0.57  0.58  0.02 -0.23  0.07
 HdGr2Y2: -0.02 -0.01 -0.06 -0.01  0.00  0.05  0.90  1.00  0.86  0.75  0.62  0.75 -0.04 -0.31  0.12
 HdGr2Y3: -0.04 -0.00 -0.03  0.11  0.04  0.16  0.81  0.86  1.00  0.84  0.60  0.73 -0.13 -0.06  0.17
HdGr2Y18: -0.04 -0.02 -0.04  0.09 -0.01  0.15  0.53  0.75  0.84  1.00  0.46  0.72 -0.21 -0.06  0.18
HdGr2Y19: -0.01  0.03 -0.03  0.01 -0.01  0.00  0.57  0.62  0.60  0.46  1.00  0.77  0.04 -0.18 -0.09
HdGr2Y24:  0.01  0.02 -0.08  0.00  0.00  0.06  0.58  0.75  0.73  0.72  0.77  1.00 -0.30 -0.26  0.12
       k: -0.06  0.14 -0.14 -0.23  0.31 -0.21  0.02 -0.04 -0.13 -0.21  0.04 -0.30  1.00 -0.13 -0.24
     tau: -0.17 -0.05  0.11  0.41  0.13  0.40 -0.23 -0.31 -0.06 -0.06 -0.18 -0.26 -0.13  1.00  0.32
    tau2:  0.03 -0.48 -0.22  0.10 -0.12  0.33  0.07  0.12  0.17  0.18 -0.09  0.12 -0.24  0.32  1.00

Explore the raw specificity indices

fprintf('\nRaw data:        SI1=%s  SI2=%s\n' ...
       ,mat2str(raw_SI1,3),mat2str(raw_SI2,3)) ;
fprintf('Raw bootstrap:   SI1=%s  SI2=%s\n' ...
       ,mat2str(B.SI1_raw(1,:),3),mat2str(B.SI2_raw(1,:),3)) ;

fprintf('\nRaw specificity indices #1 and #2:') ;
SI = [B.SI1_raw(2:end,:) B.SI2_raw(2:end,:)] ;
vn = {'SI1_EzGr1' 'SI1_EzGr2' 'SI1_HdGr1' 'SI1_HdGr2' ...
     ,'SI2_EzGr1' 'SI2_EzGr2' 'SI2_HdGr1' 'SI2_HdGr2' } ;
describe(SI) ;

CI80 = prctile(SI,[10 50 90])' ;
fprintf('\n         :   P10   P50   P90 \n--------------------------------\n') ;
for k=1:size(CI80,1)
    fprintf('%9s: %5.2f %5.2f %5.2f \n',vn{k},CI80(k,1),CI80(k,2),CI80(k,3)) ;
end

C = corrcoef(SI) ;
fprintf('\n           :') ;
for k=1:size(C,1); fprintf(' %5d',k);end
for k=1:size(C,1)
    fprintf('\n%d %9s:',k,vn{k}) ;
    fprintf(' %5.2f',C(k,:)) ;
end
fprintf('\n\n') ;
Raw data:        SI1=[0.813 -0.0377 0.912 0.146]  SI2=[0.789 0.0937 0.886 0.343]
Raw bootstrap:   SI1=[0.813 -0.0377 0.912 0.146]  SI2=[0.789 0.0937 0.886 0.343]

Raw specificity indices #1 and #2:
    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   0.822    0.189      0.29    0.70    0.80    0.92    2.66
  -0.074    0.245     -1.46   -0.19   -0.04    0.09    0.54
   0.916    0.219      0.11    0.78    0.89    1.03    1.95
   0.145    0.249     -0.65   -0.02    0.13    0.29    1.34
   0.791    0.210      0.10    0.66    0.78    0.91    1.78
  -0.291    6.056   -183.24   -0.16    0.12    0.28   11.22
   0.922    0.354     -0.47    0.71    0.87    1.04    3.48
   0.289    1.004    -12.52    0.17    0.35    0.50   23.19
------------------------------------------------------------
   0.440    1.066    -24.73    0.33    0.49    0.63    5.77

         :   P10   P50   P90 
--------------------------------
SI1_EzGr1:  0.61  0.80  1.05 
SI1_EzGr2: -0.40 -0.04  0.20 
SI1_HdGr1:  0.68  0.89  1.18 
SI1_HdGr2: -0.14  0.13  0.47 
SI2_EzGr1:  0.54  0.78  1.05 
SI2_EzGr2: -0.57  0.12  0.39 
SI2_HdGr1:  0.58  0.87  1.29 
SI2_HdGr2: -0.04  0.35  0.62 

           :     1     2     3     4     5     6     7     8
1 SI1_EzGr1:  1.00  0.02  0.25 -0.00  0.87  0.07  0.25  0.00
2 SI1_EzGr2:  0.02  1.00  0.01  0.43  0.06  0.08  0.02  0.05
3 SI1_HdGr1:  0.25  0.01  1.00  0.02  0.20  0.15  0.86  0.05
4 SI1_HdGr2: -0.00  0.43  0.02  1.00  0.07  0.03  0.02  0.16
5 SI2_EzGr1:  0.87  0.06  0.20  0.07  1.00 -0.02  0.25 -0.07
6 SI2_EzGr2:  0.07  0.08  0.15  0.03 -0.02  1.00  0.05  0.16
7 SI2_HdGr1:  0.25  0.02  0.86  0.02  0.25  0.05  1.00  0.03
8 SI2_HdGr2:  0.00  0.05  0.05  0.16 -0.07  0.16  0.03  1.00

Explore the specificity indices under the New 11-parameter model

fprintf('11-param model:  SI1=%s  SI2=%s\n' ...
       ,mat2str(param11n_fit.specif_idx1(1:2),3) ...
       ,mat2str(param11n_fit.specif_idx2(1:2),3)) ;

fprintf('\nSpecificity indices #1 and #2 under the main model:') ;
SI = [B.SI1_main(2:end,1:2) B.SI2_main(2:end,1:2)] ;
vn = {'SI1_Gr1' 'SI1_Gr2' 'SI2_Gr1' 'SI2_Gr2'} ;
describe(SI) ;

CI80 = prctile(SI,[10 50 90])' ;
fprintf('\n         :   P10   P50   P90 \n--------------------------------\n') ;
for k=1:size(CI80,1)
    fprintf('%9s: %5.2f %5.2f %5.2f \n',vn{k},CI80(k,1),CI80(k,2),CI80(k,3)) ;
end

C = corrcoef(SI) ;
fprintf('\n           :') ;
for k=1:size(C,1); fprintf(' %5d',k);end
for k=1:size(C,1)
    fprintf('\n%d %9s:',k,vn{k}) ;
    fprintf(' %5.2f',C(k,:)) ;
end
fprintf('\n\n') ;
11-param model:  SI1=[0.877 0.0328]  SI2=[0.85 0.21]

Specificity indices #1 and #2 under the main model:
    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   0.892    0.175      0.36    0.78    0.88    0.99    1.82
   0.004    0.179     -0.76   -0.10    0.02    0.13    0.42
   0.842    0.216     -0.09    0.72    0.84    0.99    1.63
   0.127    0.416     -3.45   -0.00    0.22    0.38    0.76
------------------------------------------------------------
   0.466    0.246     -0.99    0.35    0.49    0.62    1.16

         :   P10   P50   P90 
--------------------------------
  SI1_Gr1:  0.69  0.88  1.11 
  SI1_Gr2: -0.24  0.02  0.21 
  SI2_Gr1:  0.58  0.84  1.12 
  SI2_Gr2: -0.31  0.22  0.49 

           :     1     2     3     4
1   SI1_Gr1:  1.00 -0.04  0.89 -0.28
2   SI1_Gr2: -0.04  1.00  0.05  0.27
3   SI2_Gr1:  0.89  0.05  1.00 -0.36
4   SI2_Gr2: -0.28  0.27 -0.36  1.00

Explore the specificity indices under the 15-parameter model

fprintf('15-param model:  SI1=%s  SI2=%s\n' ...
       ,mat2str(indepGr_cmnKTau_fit.specif_idx1(1:2),3) ...
       ,mat2str(indepGr_cmnKTau_fit.specif_idx2(1:2),3)) ;

fprintf('\nSpecificity indices #1 and #2 under the alternative model:') ;
SI = [B.SI1_alt(2:end,1:2) B.SI2_alt(2:end,1:2)] ;
vn = {'SI1_Gr1' 'SI1_Gr2' 'SI2_Gr1' 'SI2_Gr2'} ;
describe(SI) ;

CI80 = prctile(SI,[10 50 90])' ;
fprintf('\n         :   P10   P50   P90 \n--------------------------------\n') ;
for k=1:size(CI80,1)
    fprintf('%9s: %5.2f %5.2f %5.2f \n',vn{k},CI80(k,1),CI80(k,2),CI80(k,3)) ;
end

C = corrcoef(SI) ;
fprintf('\n           :') ;
for k=1:size(C,1); fprintf(' %5d',k);end
for k=1:size(C,1)
    fprintf('\n%d %9s:',k,vn{k}) ;
    fprintf(' %5.2f',C(k,:)) ;
end
fprintf('\n\n') ;
15-param model:  SI1=[0.856 0.0601]  SI2=[0.824 0.238]

Specificity indices #1 and #2 under the alternative model:
    Mean  Std.dev       Min     Q25  Median     Q75     Max
------------------------------------------------------------
   0.856    0.149      0.35    0.75    0.85    0.94    1.58
   0.033    0.227     -1.22   -0.08    0.05    0.18    0.66
   0.828    0.192      0.11    0.70    0.82    0.94    1.81
   0.081    1.766    -52.84    0.04    0.26    0.40    0.73
------------------------------------------------------------
   0.450    0.583    -13.40    0.35    0.50    0.62    1.20

         :   P10   P50   P90 
--------------------------------
  SI1_Gr1:  0.67  0.85  1.04 
  SI1_Gr2: -0.27  0.05  0.29 
  SI2_Gr1:  0.61  0.82  1.05 
  SI2_Gr2: -0.23  0.26  0.49 

           :     1     2     3     4
1   SI1_Gr1:  1.00 -0.01  0.89  0.10
2   SI1_Gr2: -0.01  1.00  0.05  0.17
3   SI2_Gr1:  0.89  0.05  1.00 -0.01
4   SI2_Gr2:  0.10  0.17 -0.01  1.00

2010-01-29