"""
.. _ex-rsa:
====================================
Representational Similarity Analysis
====================================
Representational Similarity Analysis is used to perform summary statistics
on supervised classifications where the number of classes is relatively high.
It consists in characterizing the structure of the confusion matrix to infer
the similarity between brain responses and serves as a proxy for characterizing
the space of mental representations
:footcite:`Shepard1980,LaaksoCottrell2000,KriegeskorteEtAl2008`.
In this example, we perform RSA on responses to 24 object images (among
a list of 92 images). Subjects were presented with images of human, animal
and inanimate objects :footcite:`CichyEtAl2014`. Here we use the 24 unique
images of faces and body parts.
.. note:: This example requires the ~6 GB
:func:`~mne.datasets.visual_92_categories.data_path` dataset, so it can take
a while to run the first time.
"""
import matplotlib.pyplot as plt
import numpy as np
from pandas import read_csv
from sklearn.linear_model import LogisticRegression
from sklearn.manifold import smacof
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import StratifiedKFold
from sklearn.multiclass import OneVsRestClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
import mne
from mne.datasets import visual_92_categories
from mne.io import concatenate_raws, read_raw_fif
print(__doc__)
data_path = visual_92_categories.data_path()
fname = data_path / "visual_stimuli.csv"
conds = read_csv(fname)
print(conds.head(5))
max_trigger = 24
conds = conds[:max_trigger]
conditions = []
for c in conds.values:
cond_tags = list(c[:2])
cond_tags += [
("not-" if i == 0 else "") + conds.columns[k] for k, i in enumerate(c[2:], 2)
]
conditions.append("/".join(map(str, cond_tags)))
print(conditions[:10])
event_id = dict(zip(conditions, conds.trigger + 1))
event_id["0/human bodypart/human/not-face/animal/natural"]
n_runs = 4
fnames = [data_path / f"sample_subject_{b}_tsss_mc.fif" for b in range(n_runs)]
raws = [
read_raw_fif(fname, verbose="error", on_split_missing="ignore") for fname in fnames
]
raw = concatenate_raws(raws)
events = mne.find_events(raw, min_duration=0.002)
events = events[events[:, 2] <= max_trigger]
picks = mne.pick_types(raw.info, meg=True)
epochs = mne.Epochs(
raw,
events=events,
event_id=event_id,
baseline=None,
picks=picks,
tmin=-0.1,
tmax=0.500,
preload=True,
)
epochs["face"].average().plot()
epochs["not-face"].average().plot()
clf = make_pipeline(
StandardScaler(),
OneVsRestClassifier(LogisticRegression(C=1, random_state=79)),
)
X = epochs.get_data(tmin=0.05, tmax=0.3).mean(axis=2)
y = epochs.events[:, 2]
classes = set(y)
cv = StratifiedKFold(n_splits=5, random_state=83, shuffle=True)
y_pred = np.zeros((len(y), len(classes)))
for train, test in cv.split(X, y):
clf.fit(X[train], y[train])
y_pred[test] = clf.predict_proba(X[test])
confusion = np.zeros((len(classes), len(classes)))
for ii, train_class in enumerate(classes):
for jj in range(ii, len(classes)):
confusion[ii, jj] = roc_auc_score(y == train_class, y_pred[:, jj])
confusion[jj, ii] = confusion[ii, jj]
labels = [""] * 5 + ["face"] + [""] * 11 + ["bodypart"] + [""] * 6
fig, ax = plt.subplots(1, layout="constrained")
im = ax.matshow(confusion, cmap="RdBu_r", clim=[0.3, 0.7])
ax.set_yticks(range(len(classes)))
ax.set_yticklabels(labels)
ax.set_xticks(range(len(classes)))
ax.set_xticklabels(labels, rotation=40, ha="left")
ax.axhline(11.5, color="k")
ax.axvline(11.5, color="k")
plt.colorbar(im)
plt.show()
fig, ax = plt.subplots(1, layout="constrained")
chance = 0.5
summary, _ = smacof(chance - confusion, n_components=2, n_init=4, random_state=89)
cmap = plt.colormaps["rainbow"]
colors = ["r", "b"]
names = list(conds["condition"].values)
for color, name in zip(colors, set(names)):
sel = np.where([this_name == name for this_name in names])[0]
size = 500 if name == "human face" else 100
ax.scatter(
summary[sel, 0],
summary[sel, 1],
s=size,
facecolors=color,
label=name,
edgecolors="k",
)
ax.axis("off")
ax.legend(loc="lower right", scatterpoints=1, ncol=2)
plt.show()