Skip to content

Commit

Permalink
update to fmri_data.mean to handle selective averaging
Browse files Browse the repository at this point in the history
  • Loading branch information
torwager committed Dec 7, 2023
1 parent 43438dd commit 86cb3d7
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 7 deletions.
91 changes: 85 additions & 6 deletions CanlabCore/@image_vector/mean.m
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
% - Treats values of 0 as missing (after SPM) and excludes from mean.
%
% :Optional Inputs:
% - 'group', 'group_by' -> followed by vector of integers to define
% groups (e.g., images from the same participant). Averages across images
% within each group.
% - 'write', followed by file name
% - 'path', followed by location for file (default = current directory)
% - 'orthviews' -> show orthviews for this image, same as orthviews(m)
Expand All @@ -38,6 +41,7 @@
doplot = false;
dogroup = false;
group_by = [];
u = [];

for i = 1:length(varargin)
if ischar(varargin{i})
Expand All @@ -50,7 +54,7 @@
case {'hist', 'histogram'}, dohist = 1;
case {'orth', 'orthviews'}, doorth = 1;

case 'group'
case {'group', 'group_by'}
dogroup = true;
group_by = varargin{i+1};
group_by = categorical(group_by); % this should work for strings or numeric arrays
Expand Down Expand Up @@ -90,7 +94,8 @@
if ~isempty(obj.metadata_table)

m.metadata_table = obj.metadata_table;
m = average_metadata_table(m, group_by, u);

m = average_metadata_table(m, group_by, u); % can handle single-group case (empty grouping var) or separate groups. Need to do this even if group_by = [] so we end up with 1 row

end

Expand All @@ -100,16 +105,44 @@
m = image_vector('dat', mean(obj.dat', 1, 'omitnan')', 'volInfo', obj.volInfo, 'noverbose');
end

% Copy selected other fields
% -------------------------------
copyfield = {'source_notes','images_per_session','Y_names','Y_descrip',...
'covariate_names','additional_info','history', 'removed_voxels'};
for i = 1:length(copyfield)
m.(copyfield{i}) = obj.(copyfield{i});
end

if ~iscell(m.history) || isempty(m.history), m.history = {m.history}; end
m.history{end + 1} = 'Averaged images';
if dogroup, m.history{end} = 'Averaged images by group'; end

% Selective average by group of other fields
% -------------------------------
u = [];
m.Y = average_var_by_group(m.Y, group_by, u); % can handle single-group case (empty grouping var) or separate groups
m.covariates = average_var_by_group(m.covariates, group_by, u); % can handle single-group case (empty grouping var) or separate groups
m.X = average_var_by_group(m.X, group_by, u); % can handle single-group case (empty grouping var) or separate groups

% Recast if needed
% -------------------------------
if isa(obj, 'fmri_data_st')
m = fmri_data_st(m);
end

% Not completed for statistic_image
% if isa(obj, 'statistic_image')
% m = statistic_image(m);
% end

m.removed_voxels = obj.removed_voxels;

% Other items
% -------------------------------
% convert NaNs in means back to 0s for compatibility
m.dat(isnan(m.dat)) = 0;

% Plots and other output
% -------------------------------

if doplot || doorth
orthviews(m);
end
Expand Down Expand Up @@ -152,9 +185,11 @@


function obj = average_metadata_table(obj, group_by, u)
% average values in table

% average values in entire table if group_by is missing
if isempty(group_by)
group_by = categorical(ones(size(obj.dat, 2), 1));
group_by = ones(size(obj.metadata_table, 1), 1);
u = 1;
end

newtable = obj.metadata_table(1, :); % placeholder
Expand Down Expand Up @@ -183,3 +218,47 @@
obj.metadata_table = newtable;

end % function

% NOTES: from fmri_data_st, in case we want to use later for char and to
% print warnings
% if ~isempty(t)
% tnames = t.Properties.VariableNames;
% vars = cell(1,length(tnames));
% for i = 1:length(tnames)
% if isnumeric(t.(tnames{i}))
% vars{i} = nanmean(t.(tnames{i}));
% elseif iscell(t.(tnames{i}))
% vars{i} = t.(tnames{i})(1);
% elseif ischar(t.(tnames{i}))
% vars{i} = t.(tnames{i})(1,:);
% else
% warning(['No policy for averaging datatype ''' class(t.(tnames{i})) ''' in metadata_table. Dropping column ''' tnames{i} '''']);
% vars{i} = [];
% end
% end


function newv = average_var_by_group(v, group_by, u) % can handle single-group case (empty grouping var) or separate groups
% average values in table
if isempty(group_by)
group_by = ones(size(v, 1), 1);
u = 1;
end

newv = NaN * zeros(length(u), size(v, 2));

if isempty(v), return, end
validateattributes(v, {'numeric'})
if size(v, 1) ~= length(group_by), error('Variable and group_by vector must be the same length. Check input object fields and grouping variable'); end


for i = 1:length(u)
% for each group

wh = group_by == u(i); % this group/participant

newv(i, :) = nanmean(v(wh, :), 1);

end

end % function
12 changes: 11 additions & 1 deletion CanlabCore/Statistics_tools/contrast_code.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
%
% [vec,outnames] = contrast_code(vec)
%
% Changes values to 1, -1, or 0 for contrast coding
% Attempts to change values to 1, -1, or 0 for contrast coding
% Success depends on inputs. Check output

outnames = [];

Expand All @@ -17,6 +18,13 @@
end

elseif ~isempty(vec)

if all(vec == 0 | vec == 1) % dummy codes

vec(vec == 0) = -1;

else

wh = find(vec > 0);

vec(wh) = 1;
Expand All @@ -25,6 +33,8 @@

vec(wh) = -1;

end

end

return
Expand Down

0 comments on commit 86cb3d7

Please sign in to comment.