第04回 先行手がかり課題

実験では実際に反応が正しく行われているかチェックして、反応のエラーがあった場合にはフィードバックのメッセージを返す必要がありますが、今回は反応の評価が少し複雑です。図にまとめたので確認してください。まずキャッチ試行かどうかを判断し、キャッチ試行でかつ反応がなかった場合は正反応、あった場合にはエラーになります。キャッチ試行でない場合は、反応がなければエラー、反応があった場合でもターゲットが呈示される前に反応していた場合には予期反応ということでエラーとなります。この反応を評価する処理はBuliderのComponentでは行えないので、前回と同様にCode Componentを使います。

反応分類チャート.001

反応の評価と共にエラーメッセージも呈示しますので、Insert Routineをクリックして、trialルーチンの後ろに新しく「feedback」というルーチンを作成しましょう。その中にメッセージを表示するText componentを作成します。

feedback_routine

前回、心的回転課題で紹介したときと同じように、Textの欄には「$message」と入力し、反応の結果に応じてメッセージの内容が変わるようにします。もう一点今回は、Stopの欄の「$mes_duration」とすることで、メッセージの呈示時間も変えることとしています。これは正解の際にはメッセージを表示せず、そのまま次の試行に進むようにするためです。

fbmessage

ここでCode componentの出番です。前回の心的回転課題で説明したように反応の情報は変数に入力されています。今回は反応取得のcomponentの名前を「response」にしたので、

response.keys # 押されたキー
response.rt  # 最初に押されたキーに対する反応時間

にそれぞれの値が入っています。ただし、このresponse.rtの値には手がかりとターゲットのSOAが含まれていることに注意してください。実際に「ターゲットが出てからボタンを押すまでの」反応時間を求めるにはSOAの値を引いてあげる必要があります。

Code componentの名前は「code_fbmes」とし、Begin Routineのタブに以下の様なコードを入力します。

if response.keys == 'space':
    response.rt = response.rt-(soa-1)
    if condition == 'catch':
        response.corr =0
        mes_duration=3
        message='No target!!'
    else:
        if response.rt<0:
            response.corr=0
            mes_duration=3
            message='Too early!!'
        else:
            response.corr=1
            mes_duration=0
            message =''
else:
    if condition == 'catch':
            response.corr=1
            mes_duration=0
            message=''
    else:
        response.corr =0
        mes_duration=3
        message='You missed a target!'

trials.addData('response.rt', response.rt)
trials.addData('response.corr', response.corr)

このコードは、反応の有無・試行種類によって、反応が正解であったかどうか、フィードバックのメッセージの呈示時間、メッセージ文字列をそれぞれreponse.corr、mes_duration、messageという変数にいれるという処理を行っています。また、response.rtに入っている値が実際の反応時間と異なっているので、その修正もしています。

今回のプログラムは複数のifステートメントが入れ子状の構造になっていますので、少しわかりにくいかもしれません。わかりやすく色分けすると以下のような構造になっています。

コード構造第3回 Python言語の基礎」で解説したように、インデント(字下げ)によってヘッダ行とブロックの構造が決まります。同じ字下げの部分は一つのブロックとして認識されます。異なった数の字下げを行うことによって、複数のブロックを入れ子構造にすることができます。

まず緑のエリアが、「if response.key==’space’:」で評価された結果分岐するブロックで、反応キーがスペースキーだったときには前半のブロックが、それ以外の場合には「else:」以下の後半のブロックが実行されます。

反応があった(条件式「response.key==’space’」が真であった)場合には、以下の式が実行されます。

response.rt = response.rt-(soa-1)

これは、response.rtの値には手がかり刺激の呈示から反応までの時間が入っているので、本来の反応時間であるターゲット呈示時から時間に変換しているわけです。SOAの値には元々試行開始からのブランクの1秒間が含まれているので、soaの値から1を引いています。ちょっとややこしいですね。

上のチャートを見ると、反応があった場合には、その試行がキャッチ試行かどうかを調べ、キャッチ試行であればエラー、キャッチ試行でなければさらに反応時間をチェックしてターゲットの出現後に反応していれば正解、ターゲット出現前なら予期反応でエラーとすることになっていました。それをPythonのコードで書いたのが以下の部分です。

 if condition == 'catch':
        response.corr =0
        mes_duration=3
        message='No target!!'
    else:
        if response.rt<0:
            response.corr=0
            mes_duration=3
            message='Too early!!'
        else:
            response.corr=1
            mes_duration=0
            message =''

キャッチ試行かどうかについては、条件式「condition == ‘catch’」で判断しています。先ほど修正したresponse.rtは、ターゲット出現前に反応した場合にはマイナスの値を取りますので、条件式「response.rt<0」で条件分岐させています。

反応がなかった場合も、キャッチ試行であったかどうかで分岐して、それぞれの変数に値を代入しています。

最後に見慣れないステートメントが並んでいます。

trials.addData('response.rt', response.rt)
trials.addData('response.corr', response.corr)

これは実験終了後に結果として出力されるファイルに、今回値を入力したresponse.rt・response.corrを加えるための命令です。条件ファイルに記載した試行条件や反応時間などは自動的に結果として出力されますが、Coderコンポーネントの中で独自に作成した変数などは保存されませんので、必要に応じて結果ファイルで書き出すように命令する必要があります。シングルクォーテーション(”)で囲まれている部分がcsvファイルなどに記載されるヘッダー(見出し)の文字列で、カンマ(,)以下が保存する変数名です。

これでひとまず一連の実験の流れが完成しました。