def _stats(analysis): """2nd order stats across subjects""" # if already computed lets just load it ana_name = 'stats_' + analysis['name'] + '_vhp' if op.exists(paths('score', analysis=ana_name)): return load('score', analysis=ana_name) # gather scores across subjects scores = list() for subject in range(1, 21): kwargs = dict(subject=subject, analysis=analysis['name'] + '_vhp') fname = paths('score', **kwargs) if op.exists(fname): score, times = load(**kwargs) else: score, times = _decod(subject, analysis) scores.append(score) scores = np.array(scores) # compute stats across subjects p_values = stats(scores - analysis['chance']) diag_offdiag = scores - np.tile([np.diag(sc) for sc in scores], [len(times), 1, 1]).transpose(1, 0, 2) p_values_off = stats(diag_offdiag) # Save stats results out = dict(scores=scores, p_values=p_values, p_values_off=p_values_off, times=times, analysis=analysis) save(out, 'score', analysis=ana_name) return out
def _subscore_pipeline(analysis): # FIXME merge with subscore """Subscore each analysis as a function of the reported visibility""" ana_name = analysis['name'] + '-vis' # don't recompute if not necessary fname = paths('score', analysis=ana_name) if os.path.exists(fname): return load('score', analysis=ana_name) # gather data all_scores = list() for subject in subjects: gat, _, events_sel, events = load('decod', subject=subject, analysis=analysis['name']) times = gat.train_times_['times'] # remove irrelevant trials events = events.iloc[events_sel].reset_index() scores = list() gat.score_mode = 'mean-sample-wise' for vis in range(4): sel = np.where(events['detect_button'] == vis)[0] # If target present, we use the AUC against all absent trials if len(sel) < 5: scores.append(np.nan * np.empty(gat.y_pred_.shape[:2])) continue if analysis['name'] == 'target_present': sel = np.r_[sel, np.where( events['target_present'] == False)[0]] # noqa score = subscore(gat, sel) scores.append(score) all_scores.append(scores) all_scores = np.array(all_scores) # stats pval = list() for vis in range(4): pval.append(stats(all_scores[:, vis, :, :] - analysis['chance'])) save([all_scores, pval, times], 'score', analysis=ana_name, overwrite=True, upload=True) return all_scores, pval, times
def _correlate(analysis): """Correlate estimator prediction with a visibility reports""" ana_name = analysis['name'] + '-Rvis' # don't recompute if not necessary fname = paths('score', analysis=ana_name) if os.path.exists(fname): return load('score', analysis=ana_name) # gather data all_R = list() for subject in subjects: gat, _, events_sel, events = load('decod', subject=subject, analysis=analysis['name']) times = gat.train_times_['times'] # remove irrelevant trials events = events.iloc[events_sel].reset_index() y_vis = np.array(events['detect_button']) # only analyse present trials sel = np.where(events['target_present'])[0] y_vis = y_vis[sel] gat.y_pred_ = gat.y_pred_[:, :, sel, :] # make 2D y_pred y_pred = gat.y_pred_.transpose(2, 0, 1, 3)[..., 0] y_pred = y_pred.reshape(len(y_pred), -1) # regress R = repeated_spearman(y_pred, y_vis) # reshape and store R = R.reshape(*gat.y_pred_.shape[:2]) all_R.append(R) all_R = np.array(all_R) # stats pval = stats(all_R) save([all_R, pval, times], 'score', analysis=ana_name, overwrite=True, upload=True) return all_R, pval, times
def _subscore_pipeline(analysis): # FIXME merge with subscore """Subscore each analysis as a function of the reported visibility""" ana_name = analysis['name'] + '-vis' # don't recompute if not necessary fname = paths('score', analysis=ana_name) if os.path.exists(fname): return load('score', analysis=ana_name) # gather data all_scores = list() for subject in subjects: gat, _, events_sel, events = load('decod', subject=subject, analysis=analysis['name']) times = gat.train_times_['times'] # remove irrelevant trials events = events.iloc[events_sel].reset_index() scores = list() gat.score_mode = 'mean-sample-wise' for vis in range(4): sel = np.where(events['detect_button'] == vis)[0] # If target present, we use the AUC against all absent trials if len(sel) < 5: scores.append(np.nan * np.empty(gat.y_pred_.shape[:2])) continue if analysis['name'] == 'target_present': sel = np.r_[sel, np.where(events['target_present'] == False)[0]] # noqa score = subscore(gat, sel) scores.append(score) all_scores.append(scores) all_scores = np.array(all_scores) # stats pval = list() for vis in range(4): pval.append(stats(all_scores[:, vis, :, :] - analysis['chance'])) save([all_scores, pval, times], 'score', analysis=ana_name, overwrite=True, upload=True) return all_scores, pval, times
def _duration_toi(analysis): """Estimate temporal generalization Re-align on diagonal, average per toi and compute stats.""" ana_name = analysis['name'] + '-duration-toi' if os.path.exists(paths('score', analysis=ana_name)): return load('score', analysis=ana_name) all_scores, _, times = load('score', analysis=analysis['name'] + '-vis') # Add average duration n_subject = len(all_scores) all_score_tois = np.zeros((n_subject, 4, len(tois), len(times))) all_pval_tois = np.zeros((4, len(tois), len(times))) for vis in range(4): scores = all_scores[:, vis, ...] # align score on training time scores = [align_on_diag(score) for score in scores] # center effect scores = np.roll(scores, len(times) // 2, axis=2) for t, toi in enumerate(tois): toi = np.where((times >= toi[0]) & (times <= toi[1]))[0] score_toi = np.mean(scores[:, toi, :], axis=1) all_score_tois[:, vis, t, :] = score_toi all_pval_tois[vis, t, :] = stats(score_toi - analysis['chance']) save([all_score_tois, all_pval_tois, times], 'score', analysis=ana_name) return [all_score_tois, all_pval_tois, times]
scores = np.array([np.diag(subject) for subject in scores]) if analysis['name'] in relevant: score_relevant.append(scores) elif analysis['name'] in irrelevant: score_irrelevant.append(scores) fig, ax = plt.subplots(1, figsize=[6, 2]) # non parametric necessitate to take the mean of the sign of the effects # because each decoding score uses different metrics scores_interaction = np.mean(np.sign(score_relevant) - np.sign(score_irrelevant), axis=0) scores_relevant = np.mean(np.sign(score_relevant), axis=0) scores_irrelevant = np.mean(np.sign(score_irrelevant), axis=0) sig = stats(scores_interaction) < alpha pretty_decod(scores_relevant, times=times, ax=ax, color='y', sig=sig, fill=True, width=0.) sig = stats(scores_relevant) < alpha pretty_decod(scores_relevant, times=times, ax=ax, color='r', sig=sig) sig = stats(scores_irrelevant) < alpha pretty_decod(scores_irrelevant, times=times, ax=ax, color='w', sig=np.ones_like(times),
save(out, 'score', analysis=ana_name) return out # only recompute on the relevant analyses analyses = [ ana for ana in analyses if ana['name'] in ['target_present', 'target_circAngle'] ] for analysis in analyses: out = _stats(analysis) scores = out['scores'] if 'circAngle' in analysis['name']: scores /= 2. times = out['times'] alpha = .05 chance = analysis['chance'] p_values = stats(scores - chance) clim = np.percentile(np.diag(np.mean(scores, axis=0)), 97) clim = [chance - (clim - chance), clim] fig, ax_gat = plt.subplots(1, figsize=[7, 5.5]) pretty_gat(np.mean(scores, axis=0), times=times, sig=p_values < alpha, chance=chance, ax=ax_gat, clim=clim) report.add_figs_to_section([fig], [analysis['name']], analysis['name']) report.save()
# not 154 time points scores = np.array([np.diag(subject) for subject in scores]) if analysis['name'] in relevant: score_relevant.append(scores) elif analysis['name'] in irrelevant: score_irrelevant.append(scores) fig, ax = plt.subplots(1, figsize=[6, 2]) # non parametric necessitate to take the mean of the sign of the effects # because each decoding score uses different metrics scores_interaction = np.mean(np.sign(score_relevant) - np.sign(score_irrelevant), axis=0) scores_relevant = np.mean(np.sign(score_relevant), axis=0) scores_irrelevant = np.mean(np.sign(score_irrelevant), axis=0) sig = stats(scores_interaction) < alpha pretty_decod(scores_relevant, times=times, ax=ax, color='y', sig=sig, fill=True, width=0.) sig = stats(scores_relevant) < alpha pretty_decod(scores_relevant, times=times, ax=ax, color='r', sig=sig) sig = stats(scores_irrelevant) < alpha pretty_decod(scores_irrelevant, times=times, ax=ax, color='w', sig=np.ones_like(times), fill=True, width=0.) pretty_decod(scores_irrelevant, times=times, ax=ax, color='k', sig=sig) ax.set_ylim(-1., 1.) ax.set_yticks([-1., 1]) ax.set_yticklabels([-1, 1]) xticks = np.arange(-.100, 1.101, .100) ax.set_xticks(xticks) ax.set_xticklabels([int(1e3*ii) if ii in np.linspace(-0.1, 1., 12.) else '' for ii in xticks])
score, times = load('score', subject=subject, analysis=analysis['name']) scores.append(score) scores = [sc for sc in scores if not np.isnan(sc[0][0])] if len(scores) < 7: print('%s: not enough subjects' % analysis['name']) continue chance = analysis['chance'] alpha = 0.05 # Compute stats: is decoding different from theoretical chance level (using # permutations across subjects) print('stats', analysis['name']) p_values = stats(np.array(scores) - chance) diag_offdiag = scores - np.tile([np.diag(sc) for sc in scores], [len(times), 1, 1]).transpose(1, 0, 2) p_values_off = stats(diag_offdiag) scores_diag = [np.diag(sc) for sc in scores] p_values_diag = stats(np.array(scores_diag)[:, :, None] - chance) # Save stats results print('save', analysis['name']) out = dict(scores=scores, p_values=p_values, p_values_off=p_values_off, times=times, analysis=analysis, p_values_diag=p_values_diag)
# Init if label.name not in evokeds.keys(): evokeds[label.name] = list() evoked = np.squeeze(stc.extract_label_time_course( label, inv['src'], mode='mean', verbose=False)) evokeds[label.name].append(evoked) labels = np.array(evokeds.keys()) data = np.transpose([evokeds.values()], [0, 2, 1, 3])[0] times = stc.times # Stats on region of interest across subjects scores = list() for roi in rois: idx = np.where([roi in this_roi for this_roi in labels])[0] scores.append(np.mean(data[:, idx, :], axis=1)) p_values = stats(np.transpose(scores, [1, 2, 0]) - chance, n_jobs=-1) fig, axes = plt.subplots(len(rois), 1, sharex=True, sharey=True, figsize=[10, 40]) cmap = plt.get_cmap('rainbow') colors = cmap(np.linspace(0., 1., len(rois))) ylim = [2, -2] # Plot details_toi, details_roi = list(), list() for ii, (score, p_val, ax, color, roi) in enumerate(zip( scores, p_values.T, axes, colors, rois)): pretty_decod(score, sig=p_val < .05, times=times-np.min(times), color=color, ax=ax, fill=True, chance=chance) xlim = ax.get_xlim()
y_error = get_predict_error(gat, toi=toi_probe, sel=sel, mean=True, y_true=y_true[sel]) probas, bins = circ_tuning(y_error, n=n_bins) tuning.append(probas) results['tuning'][s, ii, jj, :, :] = np.transpose(tuning) # test significance of target versus probe train test # for biases (signed values) results['bias_pval'] = np.zeros_like((results['bias'][0])) for ii in range(2): for jj in range(2): scores = results['bias'][:, ii, jj, :, :] results['bias_pval'][ii, jj, :, :] = stats(scores) # for accuracy (absolute values) results['target_probe_pval'] = np.zeros((n_time, n_time, 2, 2)) for ii in range(2): for jj in range(2): results['target_probe_pval'][:, :, ii, jj] = stats(results['accuracy'][:, ii, jj, :, :]) # load absent target prediction to perform the control analysis of virtual # biases results['target_absent'] = np.zeros((20, n_time, 181)) results['target_absent_bias_toi'] = np.zeros((20, len(tois))) for s, subject in enumerate(subjects): # Loop across each subject print(subject)
if len(sel) == 0 or np.isnan(y_true[sel]).any(): tuning.append(np.nan * np.zeros(n_bins)) continue y_error = get_predict_error(gat, toi=toi_probe, sel=sel, mean=True, y_true=y_true[sel]) probas, bins = circ_tuning(y_error, n=n_bins) tuning.append(probas) results['tuning'][s, ii, jj, :, :] = np.transpose(tuning) # test significance of target versus probe train test # for biases (signed values) results['bias_pval'] = np.zeros_like((results['bias'][0])) for ii in range(2): for jj in range(2): scores = results['bias'][:, ii, jj, :, :] results['bias_pval'][ii, jj, :, :] = stats(scores) # for accuracy (absolute values) results['target_probe_pval'] = np.zeros((n_time, n_time, 2, 2)) for ii in range(2): for jj in range(2): results['target_probe_pval'][:, :, ii, jj] = stats( results['accuracy'][:, ii, jj, :, :]) # load absent target prediction to perform the control analysis of virtual # biases results['target_absent'] = np.zeros((20, n_time, 181)) results['target_absent_bias_toi'] = np.zeros((20, len(tois))) for s, subject in enumerate(subjects): # Loop across each subject print(subject) gat, analysis, events_sel, events = load(
overwrite=True, upload=True) return stcs, connectivity connectivity = spatial_tris_connectivity(grade_to_tris(5)) for analysis in analyses: print(analysis) # don't compute if already on S3 try: load('score_pval', subject='fsaverage', analysis=analysis['name']) continue except Exception: pass # Retrieve data chance = analysis['chance'] stcs, connectivity = _append_data(analysis) # Source Stats X = stcs - chance p_val = stats(X.transpose(0, 2, 1), connectivity=connectivity, n_jobs=1) # Save and upload save(p_val, 'score_pval', subject='fsaverage', analysis=analysis['name'], overwrite=True, upload=False)
[len(times), 1, 1]).transpose(1, 0, 2) p_values_off = stats(diag_offdiag) # Save stats results out = dict(scores=scores, p_values=p_values, p_values_off=p_values_off, times=times, analysis=analysis) save(out, 'score', analysis=ana_name) return out # only recompute on the relevant analyses analyses = [ana for ana in analyses if ana['name'] in ['target_present', 'target_circAngle']] for analysis in analyses: out = _stats(analysis) scores = out['scores'] if 'circAngle' in analysis['name']: scores /= 2. times = out['times'] alpha = .05 chance = analysis['chance'] p_values = stats(scores - chance) clim = np.percentile(np.diag(np.mean(scores, axis=0)), 97) clim = [chance-(clim-chance), clim] fig, ax_gat = plt.subplots(1, figsize=[7, 5.5]) pretty_gat(np.mean(scores, axis=0), times=times, sig=p_values < alpha, chance=chance, ax=ax_gat, clim=clim) report.add_figs_to_section([fig], [analysis['name']], analysis['name']) report.save()
gat.estimators_ = [gat.estimators_[t] for t in toi_] gat.train_times_['times'] = [gat.train_times_['times'][t] for t in toi_] gat.train_times_['slices'] = [gat.train_times_['slices'][t] for t in toi_] # predict all trials, including absent to keep cv scheme gat.predict(epochs[sel_gat]) # subscore on present only gat.scores_ = subscore(gat, sel, y[sel]) scores.append(gat.scores_) # Save classifier results save([gat, analysis, sel_gat, events], 'decod', subject=subject, analysis=analysis['name'] + '_probe_to_target') times = epochs.times[:-5] score_diag = np.array([np.diag(np.array(score)[4:, :]) for score in scores]) p_val = stats(score_diag) pretty_decod(score_diag, times=times, sig=p_val < .05, color=analysis['color'], fill=True) # toi_ = np.where((times >= toi[0]) & (times < toi[1]))[0] toi_ = np.where(p_val < .05)[0] score = np.mean(score_diag[:, toi_], axis=1) print(np.mean(score, axis=0), np.std(score, axis=0) / np.sqrt(len(score_diag)), np.min(p_val[toi_]), times[toi_])
all_score_tois[:, vis, t, :] = score_toi all_pval_tois[vis, t, :] = stats(score_toi - analysis['chance']) save([all_score_tois, all_pval_tois, times], 'score', analysis=ana_name) return [all_score_tois, all_pval_tois, times] # Main plotting colors = dict(visibility=plt.get_cmap('bwr')(np.linspace(0, 1, 4.)), contrast=plt.get_cmap('hot_r')([.5, .75, 1.])) # Loop across visibility and orientation analyses for analysis in analyses: # Plot correlation of decoding score with visibility and contrast scores, R, times = _analyze_continuous(analysis) fig, (ax1, ax2) = plt.subplots(2, 1, figsize=[20, 10]) sig = stats(R['visibility']) < .05 pretty_decod(-R['visibility'], times=times, sig=sig, ax=ax1, color='purple', fill=True) sig = stats(R['contrast']) < .05 pretty_decod(-R['contrast'], times=times, sig=sig, ax=ax2, color='orange', fill=True) report.add_figs_to_section([fig], ['continuous regress'], analysis['name']) # Plot decoding score for each visibility level all_scores, score_pvals, times = _subscore_pipeline(analysis) if 'circAngle' in analysis['name']: all_scores /= 2. # from circle to half circle figs, axes = list(), list() for vis in range(4): fig, ax = plt.subplots(1, figsize=[14, 11]) scores = all_scores[:, vis, ...]
gat, _, sel_gat, _ = load('decod', subject=subject, analysis='probe_phase') # only keep estimators after probe onset times = gat.train_times_['times'] toi_ = np.where((times >= (.800 + toi[0])) & (times < (.800 + toi[1])))[0] gat.estimators_ = [gat.estimators_[t] for t in toi_] gat.train_times_['times'] = [gat.train_times_['times'][t] for t in toi_] gat.train_times_['slices'] = [gat.train_times_['slices'][t] for t in toi_] # predict all trials, including absent to keep cv scheme gat.predict(epochs[sel_gat]) # subscore on present only gat.scores_ = subscore(gat, sel, y[sel]) scores.append(gat.scores_) # Save classifier results save([gat, analysis, sel_gat, events], 'decod', subject=subject, analysis=analysis['name'] + '_probe_to_target') times = epochs.times[:-5] score_diag = np.array([np.diag(np.array(score)[4:, :]) for score in scores]) p_val = stats(score_diag) pretty_decod(score_diag, times=times, sig=p_val < .05, color=analysis['color'], fill=True) # toi_ = np.where((times >= toi[0]) & (times < toi[1]))[0] toi_ = np.where(p_val < .05)[0] score = np.mean(score_diag[:, toi_], axis=1) print(np.mean(score, axis=0), np.std(score, axis=0) / np.sqrt(len(score_diag)), np.min(p_val[toi_]), times[toi_])
scores = list() for subject in subjects: # define path to file to be loaded score, times = load('score', subject=subject, analysis=analysis['name']) scores.append(score) scores = [sc for sc in scores if not np.isnan(sc[0][0])] if len(scores) < 7: print('%s: not enough subjects' % analysis['name']) continue chance = analysis['chance'] alpha = 0.05 # Compute stats: is decoding different from theoretical chance level (using # permutations across subjects) print('stats', analysis['name']) p_values = stats(np.array(scores) - chance) diag_offdiag = scores - np.tile([np.diag(sc) for sc in scores], [len(times), 1, 1]).transpose(1, 0, 2) p_values_off = stats(diag_offdiag) scores_diag = [np.diag(sc) for sc in scores] p_values_diag = stats(np.array(scores_diag)[:, :, None] - chance) # Save stats results print('save', analysis['name']) out = dict(scores=scores, p_values=p_values, p_values_off=p_values_off, times=times, analysis=analysis, p_values_diag=p_values_diag) save(out, 'score', analysis=('stats_' + analysis['name']), overwrite=True)
# apply morph stc_morph = morph_data_precomputed(subject, 'fsaverage', stc, vertices_to, morph) stcs.append(stc_morph.data) stcs = np.array(stcs) save([stcs, connectivity], 'score_source', subject='fsaverage', analysis=analysis['name'], overwrite=True, upload=True) return stcs, connectivity connectivity = spatial_tris_connectivity(grade_to_tris(5)) for analysis in analyses: print(analysis) # don't compute if already on S3 try: load('score_pval', subject='fsaverage', analysis=analysis['name']) continue except Exception: pass # Retrieve data chance = analysis['chance'] stcs, connectivity = _append_data(analysis) # Source Stats X = stcs - chance p_val = stats(X.transpose(0, 2, 1), connectivity=connectivity, n_jobs=1) # Save and upload save(p_val, 'score_pval', subject='fsaverage', analysis=analysis['name'], overwrite=True, upload=False)
from config import load, subjects, report fig = plt.figure(figsize=[18, 5]) axes = gridspec.GridSpec(2, 5, left=0.05, right=.95, hspace=0.35, wspace=.25) for ii, (analysis, ax) in enumerate(zip(analyses, axes)): ax = fig.add_subplot(ax) scores = list() for subject in subjects: score, times, freqs = load('score_tfr', subject=subject, analysis=analysis['name']) scores.append(score) scores = np.array(scores) if 'circAngle' in analysis['name']: scores /= 2 # compute stats p_val = stats(scores - analysis['chance']) sig = p_val < .05 # plot effect size scores = np.mean(scores, axis=0) im = ax.matshow(scores, aspect='auto', origin='lower', extent=[times[0], times[-1], 0, len(freqs)], vmin=analysis['chance'], vmax=np.max(scores), cmap=analysis['cmap']) # plot stats xx, yy = np.meshgrid(times, range(len(freqs)), copy=False, indexing='xy') ax.contour(xx, yy, sig, colors='black', levels=[0], linestyles='dotted') # pretty plot
all_score_tois[:, vis, t, :] = score_toi all_pval_tois[vis, t, :] = stats(score_toi - analysis['chance']) save([all_score_tois, all_pval_tois, times], 'score', analysis=ana_name) return [all_score_tois, all_pval_tois, times] # Main plotting colors = dict(visibility=plt.get_cmap('bwr')(np.linspace(0, 1, 4.)), contrast=plt.get_cmap('hot_r')([.5, .75, 1.])) # Loop across visibility and orientation analyses for analysis in analyses: # Plot correlation of decoding score with visibility and contrast scores, R, times = _analyze_continuous(analysis) fig, (ax1, ax2) = plt.subplots(2, 1, figsize=[20, 10]) sig = stats(R['visibility']) < .05 pretty_decod(-R['visibility'], times=times, sig=sig, ax=ax1, color='purple', fill=True) sig = stats(R['contrast']) < .05 pretty_decod(-R['contrast'], times=times, sig=sig, ax=ax2, color='orange', fill=True) report.add_figs_to_section([fig], ['continuous regress'], analysis['name'])