Diesmal machen wir da weiter, wo wir letztes Mal aufgehört haben: Wir berechnen wieder Ähnlichkeiten (als Korrelationen), vergleichen diesmal aber unabhängige Daten. Dazu teilen wir unseren Datensatz in zwei Hälften. Letztlich bedeutet das, dass wir run1 und run2 haben und den einen mit Hilfe des anderen dekodieren. Das ist eine ganz gute Übung, um irgendwann dann auch run3 dekodieren zu können.
In [1]:
import os
In [2]:
imgList = ['../training/%s'%x for x in os.listdir('../training/')]; imgList.sort()
In [3]:
imgList
Out[3]:
In [4]:
import seaborn as sns
import matplotlib.pylab as plt
%matplotlib inline
In [5]:
from nilearn import image, datasets, input_data, plotting
Hier schauen wir uns als Beispiel das letzte Bild an
In [6]:
plotting.plot_stat_map(imgList[-1],title=imgList[-1],threshold=0.8);
In [7]:
masker = input_data.NiftiMasker(mask_img='../masks/MNI152_T1_2mm_brain_mask.nii.gz',
smoothing_fwhm=8).fit()
In [8]:
masker
Out[8]:
So sieht das selbe Bild nach der Glättung aus:
In [9]:
plotting.plot_stat_map( masker.inverse_transform(masker.transform(imgList[-1])),title=imgList[-1],threshold=0.5);
Wie immer gilt: eine Tabelle ist so aufgebaut, dass die Beobachtungen (Zeitpunkte) in Zeilen sind und die Feature (Voxel) in Spalten.
In [10]:
import pandas as pd
In [11]:
def makeBigDf(imgList,masker):
bigDf = pd.DataFrame()
for img in imgList:
thisName = img.split('/')[-1].split('.')[0]
cond,num,content = thisName.split('_')
cont = '%s_%s' % (num,content)
thisDf = pd.DataFrame(masker.transform(img))
thisDf.index = [[cond],[cont]]
bigDf = pd.concat([bigDf,thisDf])
bigDf.sort_index(inplace=True)
return bigDf
In [12]:
blockDf = makeBigDf(imgList,masker)
In [13]:
blockDf
Out[13]:
Diesmal verwenden wir eine Kreuzvalidierung, das heißt wir teilen unseren Datensatz in zwei Hälften. Eine Hälfte wird benutzt um die einzelnen Blöcke vorherzusagen. Die andere Hälfte wird benutzt, um gemittelte Aktivierungsmuster für jede Bedingung zu erstellen, mit denen wir die einzelnen Blöcke korrelieren können
In [14]:
# funktion, um unsere Tabelle aufzuteilen
def makeHalfDf(bigDf,start,stop):
# leere Tabelle, in die wir 1/2 unserer Blöcke schreiben
halfDf = pd.DataFrame()
# wir gehen durch die Bedingungen (Gesichter,Wörter,etc.)
for cond in bigDf.index.levels[0]:
# wir nehmen eine Bedinung
thisDf = bigDf.ix[cond]
# und wählen nur Zeilen (Blöcke) aus, die zwischen 'start' und 'stop' liegen
thisHalf = thisDf.ix[start:stop]
# wir machen uns einen neuen index für diese Auswahl
thisHalf.index = [[cond]*thisHalf.shape[0],thisHalf.index]
# wir packen diese Auswahl zu unserer großen Tabelle
halfDf = pd.concat([halfDf,thisHalf])
# wenn wir damit fertig sind, geben wir die Tabelle aus
return halfDf
In [15]:
thisHalfDf = makeHalfDf(blockDf,0,5)
In [16]:
thisHalfDf
Out[16]:
In [17]:
otherHalfDf = makeHalfDf(blockDf,5,10)
In [18]:
otherHalfDf
Out[18]:
In [19]:
thisHalfMeanDf = thisHalfDf.groupby(level=0).mean()
In [20]:
thisHalfMeanDf
Out[20]:
In [21]:
otherHalfMeanDf = otherHalfDf.groupby(level=0).mean()
In [22]:
otherHalfMeanDf
Out[22]:
In [23]:
# wir gehen durch die Bedingungen (Gesichter,Wörter,etc.)
for cond in thisHalfMeanDf.index:
# Abbildung mit zwei Teilen (links und rechts)
fig,(ax1,ax2) = plt.subplots(1,2,figsize=(16,4))
# Auswahl der Bedingung aus der ersten Tabelle
thisA = masker.inverse_transform(thisHalfMeanDf.ix[cond])
# Auswahl der Bedingung aus der zweiten Tabelle
thisB = masker.inverse_transform(otherHalfMeanDf.ix[cond])
# Abbildungsteil links, mit Daten der ersten Tabelle)
display = plotting.plot_stat_map(thisA,title='%s, 1st half'%cond,threshold=0.2,axes=ax1)
# Abbildungsteil rechts, mit Daten der zweiten Tabelle
plotting.plot_stat_map(thisB,title='%s, 2nd half'%cond,threshold=0.2,axes=ax2,cut_coords=display.cut_coords)
# Abbildung zeigen
plt.show()
In [24]:
import numpy as np
In [25]:
# wir nehmen die Mittelungen der beiden Hälften und packen sie zusammen
myMeanDf = pd.concat([thisHalfMeanDf,otherHalfMeanDf])
# wir machen einen Index, der uns sagt welche Zeilen zu welcher Hälfte gehören
myMeanDf.index = [ np.concatenate([ ['1st half']*5,['2nd half']*5 ]),myMeanDf.index ]
In [26]:
myMeanDf
Out[26]:
In [27]:
# wir korrelieren alle Bedingungen mit allen anderen (wobei wir für jede
# Bedinung zwei Variaten haben: einmal die Variante aus der ersten Hälfte
# und einmal die Variate aus der zweiten Hälfte)
meanCorrDf = myMeanDf.T.corr()
In [28]:
meanCorrDf
Out[28]:
In [29]:
plt.figure(figsize=(16,16))
sns.heatmap(meanCorrDf,square=True,vmin=-1,vmax=1,annot=True)
plt.yticks(rotation=90)
plt.xticks(rotation=90)
plt.show()
In [30]:
plt.figure(figsize=(8,8))
sns.heatmap(meanCorrDf.ix['1st half']['2nd half'],square=True,vmin=-1,vmax=1,annot=True)
plt.show()
Das hier ist jetzt so, wie die Vorhersagen in der letzten Sitzung, nur das wir jeden Block von run 1 mit den Mittelungen aus run 2 Vergleichen.
In [31]:
myCorrDf = pd.DataFrame(np.corrcoef(thisHalfMeanDf,otherHalfDf)[5:,:5],
index=thisHalfDf.index,
columns=otherHalfMeanDf.index)
In [32]:
plt.figure(figsize=(12,10))
sns.heatmap(myCorrDf,annot=True)
plt.show()
In [33]:
def makeCorrPred(myCorrDf):
d = {}
# wir gehen durch jede Zeile
for cond,num in myCorrDf.index:
# wir wählen diese Zeile aus
thisDf = myCorrDf.ix[cond].ix[num]
# wir wählen die Spalte mit dem höhsten Wert aus
winner = thisDf.idxmax()
# wir schreiben einen eintrag mit folgenden infos:
# real : die tatsächliche bedingung (aus der zeile)
# winner: die spalte mit der höchsten korrelation
# hit: wir fragen, ob real und winner identisch sind (kann wahr oder falsch sein)
d[num] = {'real':cond, 'winner':winner,'hit':cond==winner }
# wir packen das ganze in eine tabelle, die wir nett formatieregn
predDf = pd.DataFrame(d).T
# wir rechnen aus, in wie viel prozent der Fälle wir richig lagen
percentCorrect = np.mean( [int(x) for x in predDf['hit']] )*100
return predDf,percentCorrect
In [34]:
corrPredDf,corrPcCorrect = makeCorrPred(myCorrDf)
In [35]:
corrPredDf
Out[35]:
In [36]:
print "%i%% richtige Vorhersagen!" % corrPcCorrect
Es fällt auf: wir hatten vorher 90% richtig, jetzt sind es nur noch 76%.
In [37]:
myCorrDf = pd.DataFrame(np.corrcoef(thisHalfMeanDf,otherHalfDf)[5:,:5],
index=thisHalfDf.index,
columns=thisHalfMeanDf.index)
corrPredDf,corrPcCorrect = makeCorrPred(myCorrDf)
print "%i%% richtige Vorhersagen!" % corrPcCorrect
In [38]:
myCorrDf = pd.DataFrame(np.corrcoef(thisHalfMeanDf,otherHalfDf)[5:,:5],
index=thisHalfDf.index,
columns=otherHalfMeanDf.index)
corrPredDf,corrPcCorrect = makeCorrPred(myCorrDf)
print "%i%% richtige Vorhersagen!" % corrPcCorrect
In [39]:
myCorrDf = pd.DataFrame(np.corrcoef(thisHalfMeanDf,thisHalfDf)[5:,:5],
index=thisHalfDf.index,
columns=thisHalfMeanDf.index)
corrPredDf,corrPcCorrect = makeCorrPred(myCorrDf)
print "%i%% richtige Vorhersagen!" % corrPcCorrect
In [40]:
myCorrDf = pd.DataFrame(np.corrcoef(otherHalfMeanDf,otherHalfDf)[5:,:5],
index=otherHalfDf.index,
columns=otherHalfMeanDf.index)
corrPredDf,corrPcCorrect = makeCorrPred(myCorrDf)
print "%i%% richtige Vorhersagen!" % corrPcCorrect
76% richtiger Antworten für unabhängige Daten ist bei einer Ratewahrscheinlichkeit von 20% schon nicht schlecht. Aber unser Ziel ist natürlich, an 100% heranzukommen und dazu müssen wir Feature Selection betreiben. Das heißt, wir können nicht einfach Alles mit Allem korrelieren, sondern sollten Voxel aussuchen, die besonders bedeutsam sind.
In [ ]: