diff --git a/signal_detection.py b/signal_detection.py index 6fe08e1235b0b97f7c73ad67f81266cbc8f2efa7..7fc41187f5eb0482a1c1e8f3deb14ecb7fe70787 100644 --- a/signal_detection.py +++ b/signal_detection.py @@ -1,5 +1,6 @@ import numpy as np import pandas as pd +pd.set_option('precision',2) from psychopy import core, visual, event, monitors from imageio import imread @@ -63,6 +64,9 @@ def load_data(subject): 'trial':[], 'stimulus':[], 'response':[], + 'hit':[], + 'false_alarm':[], + 'correct':[], 'RT':[]} data = pd.DataFrame(data) return data @@ -191,9 +195,12 @@ def run_block(subject,intensity,p=0.5,task='yes-no'): 'block': block, 'intensity': intensity, 'p': p, - 'trial': i, - 'stimulus': s, - 'response': r, + 'trial': int(i), + 'stimulus': int(s), + 'response': int(r), + 'hit': int(s and r), + 'false_alarm': int(not(s) and r), + 'correct': int(s==r), 'RT': rt} data = data.append(ndata, ignore_index=True) # after a number of trials have been done save and quit @@ -203,3 +210,26 @@ def run_block(subject,intensity,p=0.5,task='yes-no'): win.close() core.quit() return data + +def summarize(data, group = ['intensity','p'], mode='all'): + grouped = data.groupby(group) + # hit rate + N1 = grouped['stimulus'].sum() + H = grouped['hit'].sum() / N1 + # false alarm rate + N0 = grouped.size()-grouped['stimulus'].sum() + FA = grouped['false_alarm'].sum() / N0 + # percent correct + N = N0 + N1 + PC = grouped['correct'].sum() / N + # aggregate + if mode == 'pc': + summary = pd.DataFrame([PC, N]).T + summary.columns=['PC','N'] + elif mode == 'roc': + summary = pd.DataFrame([FA, H, N0, N1]).T + summary.columns=['FA','H','N0','N1'] + elif mode == 'all': + summary = pd.DataFrame([FA, H, PC, N0, N1, N]).T + summary.columns=['FA','H','PC','N0','N1','N'] + return summary diff --git a/signal_detection_tutorial.ipynb b/signal_detection_tutorial.ipynb index 8121efa73a5fbaf28dc718bf93437354130924b6..0fc15956eb122f8eda01ec01639b94eca880c7d0 100644 --- a/signal_detection_tutorial.ipynb +++ b/signal_detection_tutorial.ipynb @@ -55,7 +55,10 @@ "metadata": {}, "source": [ "## The Yes-No Task\n", - "\n" + "\n", + "The first idea one could have is the following: We choose an intensity, show the *A* with this intensity to a subject 100 times and record how often the subject reports to see the *A*. The trouble with this experiment ist that the subject could just lie and always say \"I see it\". A simple fix is to introduce catch trials. On each trial we flip a coin an there either is (signal trial) or there is not (noise-only or catch trial) an *A*. In this way we can offer the performance objectively.\n", + "\n", + "A block in the experiment will always consist of 50 trials. In each trial you will first see a fixation cross that you should look at. Then, very briefly, the stimulus will show up. With probability `p=0.5` there will be an *A*. Your task is to then press either `y` (for yes) or `n` (for no) to answer the question whether you detected the *A*. Let's try this:" ] }, { @@ -64,15 +67,14 @@ "metadata": {}, "outputs": [], "source": [ - "subject = 'test' # put in your intials here\n", - "run_block(subject,100) # and run this cell by shift+enter" + "data = run_block(subject='test',intensity=100) # run this cell by shift+enter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Psychometric Functions" + "This was an easy block with a high intensity (`intensity=100`). Let's look at how well you did." ] }, { @@ -81,9 +83,31 @@ "metadata": {}, "outputs": [], "source": [ - "int(np.random.rand()<0.5)" + "data = load_data('test')\n", + "summarize(data,'block',mode='pc')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The first column (block) shows you the blocks you've done and the other colums how many trials you did and how well you did in each block. The first thing you want to look at is the column N. It says you did 50 trials. The column PC shows the proportion correct. Since this was an easy block hopefully the number will be close to 1. If not you need to practice this task a little more until you make only 1 or 2 mistakes in a block of 50 trials. These mistakes are not because you didn't see the *A* but because you accidentally pressed the wrong button. As the task is pretty fast paced this can happen and it's really hard to bring down the number of mistakes down to zero even if you see all *A*s. As we want to measure how well you can see the *A* it's important that you really learn the response mapping and make as few \"finger errors\" as possible. So really do practice this task by re-running the `run_block`-cell above (with `subject='test'` and a clearly visible `intensity=100`) before you move on." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Psychometric Functions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, { "cell_type": "markdown", "metadata": {},