Home > database > ensemble_response_qa.m

ensemble_response_qa

PURPOSE ^

Performs quality-control on response data

SYNOPSIS ^

function out_st = ensemble_response_qa(data_st,params)

DESCRIPTION ^

 Performs quality-control on response data 
 out_st = ensemble_response_qa(data_st,params);

 Calculates the standard deviation of response values across the
 questions on the forms present in the response data that are entered in
 data_st and optionally specified as filtering criteria in the params
 struct.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function out_st = ensemble_response_qa(data_st,params)
0002 % Performs quality-control on response data
0003 % out_st = ensemble_response_qa(data_st,params);
0004 %
0005 % Calculates the standard deviation of response values across the
0006 % questions on the forms present in the response data that are entered in
0007 % data_st and optionally specified as filtering criteria in the params
0008 % struct.
0009 
0010 % 02May2013 Petr Janata
0011 % 05Jul2013 PJ - added formatting for convenient output string
0012 % 21Oct2015 PJ - enhanced analyses and reporting - optional check for
0013 %                minimum number of iterations of specified forms
0014 
0015 out_st = [];
0016 
0017 % Make sure we have a form_id variable
0018 if ~strcmp('form_id',data_st.vars)
0019   fprintf('%s: No form_id data found. Exiting ...\n', mfilename);
0020   return
0021 end
0022 cols = set_var_col_const(data_st.vars);
0023 
0024 % Set up reporting
0025 if isfield(params,'report')
0026   fid = ensemble_init_fid(params.report);
0027 else
0028   fid = 1;
0029 end
0030 
0031 % Check to see whether a minimum standard deviation criterion was
0032 % specified. Otherwise, use zero.
0033 if isfield(params, 'sdCrit')
0034   sdCrit = params.sdCrit;
0035 else
0036   sdCrit = 0;
0037 end
0038 
0039 % Filter the input data
0040 if isfield(params,'filt')
0041   data_st = ensemble_filter(data_st, params.filt);
0042 end
0043 
0044 % Identify the list of unique forms and make a mask matrix
0045 [formMaskMtx, formids] = make_mask_mtx(data_st.data{cols.form_id}); % Generate a form mask matrix
0046 nforms = length(formids);
0047 
0048 % Get a list of subjects
0049 subids = unique(data_st.data{cols.subject_id});
0050 nsubs = length(subids);
0051 
0052 % Initialize accumulator variables
0053 out_st.vars = {'subject_ids','form_ids','std_dev','suspect','insufficient','numCleanIter'};
0054 ocols = set_var_col_const(out_st.vars);
0055 out_st.data{ocols.subject_ids} = subids;
0056 out_st.data{ocols.form_ids} = formids;
0057 out_st.data{ocols.std_dev} = nan(nsubs, nforms);
0058 
0059 if isfield(params,'form')
0060   minimumIterationForms = fieldnames(params.form);
0061 else
0062   minimumIterationForms = {};
0063 end
0064 if ~isempty(minimumIterationForms)
0065   for iform = 1:length(minimumIterationForms)
0066     minIterFormIDs(iform) = params.form_id_const.(minimumIterationForms{iform});
0067   end
0068 else
0069   minIterFormIDs = [];
0070 end
0071 nminIter = length(minIterFormIDs);
0072 out_st.data{ocols.insufficient} = nan(nsubs, nminIter);
0073 out_st.data{ocols.numCleanIter} = nan(nsubs, nminIter);
0074 
0075 % Get an overall nanmask
0076 nanmask = isnan(data_st.data{cols.response_enum});
0077 
0078 % Loop over subjects
0079 for isub = 1:nsubs
0080   currSub = subids{isub};
0081   
0082   % Create a subject mask
0083   submask = ismember(data_st.data{cols.subject_id}, currSub);
0084   
0085   % Loop over forms
0086   for iform = 1:nforms
0087     compositeMask = submask & formMaskMtx(:,iform);
0088     out_st.data{ocols.std_dev}(isub,iform) = nanstd(enum2data(data_st.data{cols.response_enum}(compositeMask)));
0089     
0090     % Check whether this form is on the list of minimum iteration checks
0091     fidx = find(minIterFormIDs == formids(iform));
0092     if ~isempty(fidx)
0093       minCleanIter = params.form.(minimumIterationForms{fidx}).minimumCleanIterations;
0094       numCleanIter = length(unique(data_st.data{cols.response_order}(compositeMask & ~nanmask)));
0095       out_st.data{ocols.numCleanIter}(isub,fidx) = numCleanIter;
0096       
0097       if numCleanIter < minCleanIter
0098         out_st.data{ocols.insufficient}(isub,fidx) = 1;
0099       end
0100     end
0101     
0102   end % for iform=
0103 end % for isub
0104 
0105 % Now check for potentially bad subjects
0106 data = out_st.data{ocols.std_dev};
0107 nanMask = any(isnan(data),2);
0108 sdMask = any(data <= sdCrit, 2);
0109 insuffMask = any(out_st.data{ocols.insufficient},2);
0110 problemMask = nanMask | sdMask | insuffMask;
0111 
0112 out_st.data{ocols.suspect} = subids(problemMask);
0113 nprob = sum(problemMask);
0114 if nprob
0115   fprintf(fid,'%s: Identified %d potentially problematic subjects\n', mfilename, sum(problemMask));
0116 
0117   % Handle subjects with NaNs
0118   probSubs = subids(nanMask);
0119   fprintf(fid, '\n\n%d subjects missing responses on some forms\n', length(probSubs));
0120   for iprob = 1:sum(nanMask)
0121     fprintf(fid, 'Subject %s missing a total of %d responses in encounters with form(s): %s\n', probSubs{iprob}, ...
0122       sum(isnan(data(strcmp(probSubs{iprob}, subids),:))), ...
0123       sprintf('%d, ',formids(isnan(data(strcmp(probSubs{iprob},subids),:)))));
0124   end
0125   outstr = sprintf('''%s'',', probSubs{:});
0126   outstr(end) = '';
0127   fprintf(fid, '\ndefs.suspect.missingResponses = {%s};', outstr);
0128   
0129   % Handle subjects with no variability
0130   probSubs = subids(sdMask);
0131   fprintf(fid, '\n\n%d subjects with no variability on some forms\n', length(probSubs));
0132   for iprob = 1:sum(sdMask)
0133     fprintf(fid, 'Subject %s had no variability on form(s): %s\n', probSubs{iprob}, ...
0134       sprintf('%d, ',formids(data(strcmp(probSubs{iprob},subids),:) <= sdCrit)));
0135   end
0136   outstr = sprintf('''%s'',', probSubs{:});
0137   outstr(end) = '';
0138   fprintf(fid, '\ndefs.suspect.responseVariability = {%s};', outstr);
0139     
0140   % Handle subjects with an insufficient number of trials
0141   probSubs = subids(insuffMask);
0142   fprintf(fid, '\n\n%d subjects with fewer than %d iterations of required forms\n', length(probSubs), minCleanIter);
0143   for iprob = 1:sum(insuffMask)
0144     fprintf(fid, 'Subject %s had insufficient (< %d) iterations of form(s): %s\n', probSubs{iprob}, ...
0145       minCleanIter, ...
0146       cell2str(minimumIterationForms(out_st.data{ocols.insufficient}(strcmp(subids,probSubs{iprob}),:)),','));
0147   end
0148   outstr = sprintf('''%s'',', probSubs{:});
0149   outstr(end) = '';
0150   fprintf(fid, '\ndefs.suspect.tooFewTrials = {%s};', outstr); 
0151   
0152 end
0153 
0154 if fid > 1
0155   fclose(fid);
0156 end
0157 
0158 
0159 return

Generated on Wed 20-Sep-2023 04:00:50 by m2html © 2003