6. 反応にフィードバックしよう―概念識別

6.1. この章の実験の概要

ずっと視知覚の実験ばかりが続いたので、この章では概念識別の実験を取り上げましょう。私たちが新しい概念を学ぶときには講義を聞いたり書籍を読んだりといった言語を通じた手段を用いることが多いでしょう。その他にも、ある概念について「この事例は当てはまる」、「あの事例は当てはまらない」といった事例を経験することによって、概念を獲得することがあります。例えば、幼児が言語を獲得する時に「これは『くるま』じゃないよ」、「いま『くるま』がみえたね」といった事例を通じて「くるま」という概念を獲得するといった具合です。ある概念が適用される事例を正事例、適用されない事例を負事例と呼びます。この章で取り上げる概念識別の実験は、この事例を通じた概念の獲得過程を単純化したものです。

実験では 図6.1 に示す画像を刺激として使用します。眼鏡の有無(かけている/かけていない)、顔の形(丸い/四角い)、目の大きさ(大きい/小さい)、眉毛の形(上がっている/下がっている)、口の形(口角が上がっている/下がっている)の5種類の次元の組み合わせで合計2の5乗=32種類の顔画像を用います。これらの画像ファイルは 図6.1 下に示すように、'Face'+5桁の数値+'.png'という名前で保存され、数値の各桁の値が5種類の次元の値に対応しています。

実験の最初に無意味な単語をひとつ決定します。以後、この単語を「ターゲット語」と呼びます。例えば今、ターゲット語として「リニ」という無意味な単語を選んだとしましょう。この「リニ」の正事例として、5種類の次元のいずれを選んでその値のどちらかを割り当てます。例えば「眼鏡の有無」の「かけていない」を選んだとしましょう。そうすると、これから実施する実験では「リニ」は刺激の顔が「眼鏡をかけていない」時に「当てはまる」、それ以外の時に「当てはまらない」ということになります。

_images/stimul-concept-identification.png

図6.1 実験に用いる刺激。5次元の特徴にそれぞれ2種類の値があり、合計2の5乗=32種類の画像あります。

以上のことを決めたうえで、実験に入ります。実験は1回から複数回のセッションから成っています( 図6.2 )。各セッションの最初には、先ほど決定したターゲット語と、反応方法の教示が表示されます。反応方法は「当てはまる」ならばカーソルキーの左、「当てはまらない」ならカーソルキーの右を押すことにしましょう。実験参加者が教示画面でカーソルキーの左右いずれかを押すと最初の試行が始まります。各試行では、スクリーン中央にターゲット語と顔画像が提示され、スクリーン左下に「当てはまる」、右下に「当てはまらない」と提示されます。実験参加者はこの顔画像がターゲット語に「当てはまる」か「当てはまらない」か判断して、キーを押して反応します。反応に制限時間は設けず、刺激は反応があるまで提示し続けます。反応の検出後に、反応が正解であれば「正解です」、誤答であれば「不正解です」とスクリーンに表示して正誤を実験参加者にフィードバックします。32種類の全ての画像に対して一回ずつ判断するまで試行を繰り返し、終了したら実験参加者に正事例の条件を口頭で回答させ、実験者は筆記します。以上の手続きを1セッションとします。本来なら参加者の回答をキーボードで文章として入力してもらいたいところですが、PsychoPyで文章入力をするのはちょっと難しいので今回はこういう形を取ります((「 9.5:TextBoxコンポーネントで文字を入力してみよう 」も参照のこと)。実際の実験では複数セッション実施するでしょうが、複数セッションは 第4章 の多重ループで簡単に実現できますので、この章では1セッションのみを完成させることを目指しましょう。

_images/concept-identification-procedure.png

図6.2 実験の概要。

以上が実験の概要です。実験の作成に入る前に、実験の作成に必要となる新しいコンポーネントの紹介をします。

6.2. Imageコンポーネント

Imageコンポーネントは [画像] で指定した画像ファイルをスクリーンに描画するコンポーネントです( 図6.3 )。Gratingコンポーネントと共通する部分が多く、Gratingコンポーネントと同様に [マスク][テクスチャの解像度 $][補間] というプロパティがあります。これらのプロパティについては 第4章 を参考にしてください。

_images/image-component.png

図6.3 Imageコンポーネント

他コンポーネントと共通のプロパティのうち、注意が必要なのが [サイズ [w, h] $][前景色] です。 まず [サイズ [w, h] $] ですが、ここを空欄にすると画像ファイルの本来の大きさで描画します。つまり、幅640pix、高さ480pixの画像であればそのまま幅640pix、高さ480pixで描かれるということです。 これがどういう時に役に立つかというと、ループを使って縦横比が異なる画像ファイルを次々と表示するようなケースです。この時 [サイズ [w, h] $] を指定してしまうと、常に指定された縦横比で描かれるので、画像によって横方向か縦方向に引き延ばされてしまいます。ただ、この方法はheight単位のようにスクリーンの解像度に応じて刺激の大きさを調整してくれる機能と相性がよくありません。フルHD(解像度1920×1080)のモニターではいい感じの大きさで表示されるのに、4K(解像度3840×2160)のモニターだと小さすぎて刺激がよく見えないといったことが起こり得ます。実験室で、常に同じ解像度のモニターで実行するのでしたら問題にならないでしょうが、デモ用に公開する実験やオンライン実験のように、どのような解像度のモニターで実行されるかわからない実験には不向きです。

height単位の場合にスクリーンとの相対値で画像の大きさを指定しつつ、画像ごとに縦横比を変更したい場合は、条件ファイルを使って画像ごとに [サイズ [w, h] $] を指定する必要があります(実行中に画像の縦横比を計算することも可能ですが、本書で想定しているレベルを超えます)。あるいは、そういう面倒なことにならないように画像の縦横比がすべて同じになるように画像を用意するのもよいでしょう。

もうひとつの要注意プロパティである [前景色] ですが、画像を描画する際に、ここに指定した色と画像の色の乗算がおこなわれます。つまり、画像上のある位置の色がPsychoPy風の表現で(-0.3, 0.5, 0.7)であるときに [前景色] に$(-1.0, 0.0, 0.3)と指定されていたら、RGB各成分をそれぞれ乗算して(0.3, 0.0, 0.21)として描かれるということです。これを使うと、R成分だけを描画するとかG成分だけを反転するといった簡単な画像処理だったら、前もって処理をおこなった画像ファイルを用意しなくても実行時に処理できるということです。 [前景色] の初期値は$(1, 1, 1)ですので、乗算しても何も起こらずに画像の色そのままに描画されます。

Imageコンポーネントで初登場のプロパティは [水平に反転][垂直に反転][画像] です。 [水平に反転][垂直に反転] にチェックを入れておくと、それぞれ画像が左右反転、上下反転された状態で提示されます。 [画像] には画像ファイル名を指定します。条件ファイルと同様に、ただファイル名だけが与えられた場合には、実行しているpsyexpファイルと同じフォルダからファイルを探します。当然ファイルが見つからなければエラーとなり実験は停止してしまいます。psyexpと異なるフォルダにある画像ファイルを参照する場合は、絶対パスおよび相対パスによる指定が使えます。絶対パス、相対パスと言われてもピンと来ない方もおられると思いますので、節を改めて解説しておきましょう。

チェックリスト
  • 画像ファイルをスクリーン上に提示することができる。

  • 画像ファイルを上下、または左右に反転させて提示することができる。

6.3. 絶対パスと相対パス

パス(path)とは「小道」のことで、PCではプログラムを実行するときに開いたり保存したりしたいファイルへたどり着くための経路を表します。私たちの身の回りのものに例えるとすれば、「住所」によく似ています。「X県Y市Z町1丁目1-1」という住所があるとして、手紙の宛先にこの住所を書いておけば、全国どこから発送しても同じところへ配送されます。PCの場合でも同様に、PCのファイルシステム(ハードディスクやUSBメモリ等)でファイルの位置を特定できる「住所」があります。この住所を絶対パスと呼びます。

Microsoft Windowsの場合、USBメモリを差し込むと「ドライブF:」などのようにアルファベットが割り当てられるのは御存知のことと思います。このアルファベットをドライブレターと呼びます。このUSBメモリに「psychology」というフォルダがあって、さらにその中に「report」というフォルダがあって、その中の「report01.docx」というファイルがあるとします。このreport01.docxを絶対パスで表すには、以下のようにドライブレターの後にコロンとバックスラッシュを書き、以後フォルダ名をバックスラッシュで区切って記述します。

F:\psychology\report\report01.docx

日本語Windowsではバックスラッシュは半角の円記号(¥)で表示されますのでご注意ください(「 3.11.5:$を含む文字列を提示する 」を参照)。日本での住所の表記が都道府県、市町村、と大きな区分から小さな区分に向かって書かれるのと似ています。

UbuntuなどのLinux系OSでは、バックスラッシュではなく以下のようにスラッシュでフォルダを区切ります。また、ドライブレターは使用されず、絶対パスの先頭はスラッシュです。

/home/user/Documents/Report/report01.txt

言うなれば先頭のスラッシュの前に「名前がない」フォルダがあることになりますが、この名無しフォルダの事をrootと呼びます。ファイルシステムがこの名無しフォルダを根として枝が広がっていくように見えるところに由来する名称です。

絶対パスの良いところは、どの位置に目的のファイルがあるかを曖昧さなしに特定できることです。学期末のレポートの時期に「○○概論」や「△△特殊講義」といったあちこちのフォルダにreport.docという名前のファイルが散らかっていて訳が分からなくなることがありますが、絶対パスであればどのフォルダのreport.docであるかを見失うことがありません。しかし、この性質が逆に「融通の利かなさ」という欠点になる場面もあります。例えば自宅のPCでUSBメモリがF:ドライブとして接続されていて、その中にあるF:\Exp07\stim01.jpgという刺激画像をBuilderから絶対パスで参照するようにしたとします。そしてpsyexpファイルを保存して大学の実験室へ入り、実験室のPCにUSBメモリを接続したら、E:ドライブとして認識されてしまったとしましょう。そうするとpsyexpファイルで参照しているF:\Exp07\stim01.jpgの絶対パスは今やE:\Exp07\stim01.jpgに変わっていますので、それに合わせてpsyexpファイルを書き換えないといけません。これはあまりにも面倒です。このようなときに便利なのが相対パスによる指定です。

相対パスとは、住所の例えで言うならば、何県の話をしているのか文脈から明らかなときに県を省略して「Y市Z町1丁目1-1」のように書くことに似ています。しかし、住所の例えではPCの相対パスは上手く説明できません。PCの相対パスでは、まず基準となる位置を決めて、そこから住所をどのように辿っていくかを記述します。基準となる位置のことをカレントフォルダと呼びます。今、F:\experiment\exp01というフォルダにexp01.psyexpというBuilderの実験ファイルがあるとしましょう( 図6.4 )。このexp01.psyexpを実行する時には、F:\experiment\exp01がカレントフォルダとなります。exp01.psyexpから他のファイルを探す時、絶対パスではないパス(ドライブレターやrootから始まっていない書き方)が与えられると、カレントフォルダからファイルを探します。第3章 以降で条件ファイルを指定する時にexp01cnd.xlsxという具合にファイル名だけを書いたことを思い出してください。これは絶対パスではないので、カレントフォルダであるF:\experiment\exp01のexp01cnd.xlsxを指すことになります( 図6.4 (1))。image\stim01.pngと指定されたら、カレントフォルダの中に含まれるimageというフォルダの中にあるstim01.pngを指していると解釈されます( 図6.4 (2))。このようなカレントフォルダを基準にした指定方法を相対パスと呼びます。

_images/path-example.png

図6.4 相対パスによるファイルの指定。

普通の住所の表記と相対パスが大きく異なるのは、相対パスには階層をさかのぼる記法が用意されている点です。相対パスの中にピリオドが2文字だけのフォルダ( ..\ )が含まれていると、それは現在のフォルダを含んでいる上位のフォルダを指します。 図6.4 の例では、..\がF:\experimentを指します。この記法は重ねて使用することができるので、..\..\と書くとF:\experimentのさらに上位のフォルダであるF:\を指します。..\で指し示される上位フォルダのことを親フォルダと呼びます。この記法を用いることによって、カレントフォルダより上位のフォルダに含まれるファイルでも自在に指定することができます。 図6.4 の(3)のexp02cnd.xlsxへ到達するためにはまず..\で親フォルダに移動し、そこからexp02フォルダへ下ればたどり着けますから..\exp02\exp02cnd.xlsxと書きます。同様に(4)のface001.jpgにたどり着くためには、..\..\と書いて親フォルダを二つ遡ってF:\まで移動し、そこからphotoフォルダ、faceフォルダと下ればたどり着きますから..\..\photo\face\face001.jpgと書けばよいということです。Builderで大量の画像ファイルを刺激として使う場合や、複数の実験で同じ画像を使いまわす場合などには、この相対パスの表記法を覚えておくと必ず役に立ちます。しっかり理解しておきましょう。

相対パスのもう一つの利点は、「相対パスを使えばPythonがOSによるパスの区切り文字の違いを吸収してくれる」という点です。先ほどから繰り返し例を示しているように、Microsoft Windowsではフォルダ名を区切る文字としてバックスラッシュを用います。ですから、Windows上で動作するプログラムで相対パスを記述する時にはimage\stim01.pngという具合に書かなければいけません。しかし、先述のようにLinuxではスラッシュで区切りますので、Windows上で動いたプログラムをそのまま持ってきても動作しません。この問題は「個人用PCはWindowsだけど大学の実験室ではLinux」といった状況では困りものなのですが、ありがたいことにWindows版のPythonにはパスをLinux流にimage/stim01.pngと書いても適切に解釈してくれる機能があります。ですから、Linux流の相対パスを書いておけばWindowsでもLinuxでも動作するBuilderの実験を作ることができるのです。「Windows上でもスラッシュをパスの区切り文字と見なしてくれる機能は絶対パスの時にも有効なんじゃないの?」と思われる方もいるかも知れませんが、絶対パスの場合はドライブレターの問題が立ちはだかります。さすがのPythonでもドライブレターを自動的に補ったり削除したりはできませんので、絶対パスで書くとOS依存になってしまいます。

最後に、親フォルダの記法を紹介したついでに、カレントフォルダの記法も一応紹介しておきます。ピリオド1文字だけのフォルダ名はカレントフォルダとして解釈されます。ですから、 図6.4 の(1)は.\exp01cnd.xlsxとも書くことができます。 (2)も同様に.\image\stim01.pngと書くことができます。Builderを使うだけでしたら覚える必要はないのですが、今後本格的なプログラミングを学習したりする時には知っていると役に立つかもしれません。

チェックリスト
  • 画像ファイルや条件ファイル等の位置を絶対パスで指定することができる。

  • 画像ファイルや条件ファイル等の位置を相対パスで指定することができる。

  • OSによるパスの書き方の違いを説明できる。

  • 複数のOSで実行できるBuilderの実験を作成するためにはどの記法でパスを記述したらよいか答えられる。

6.4. 実験の作成

コンポーネントの解説が終わったので、実験の作成に入りましょう。この章の解説では、Builderで実験を新規作成し、以下の作業を行ってexp06.psyexpの名前で保存したものとします。

  • 実験設定ダイアログ

    • [実験情報ダイアログ] にwordという項目と、conditionという項目を追加する。

    • PsychoPyの設定でheight以外の単位を標準に設定している場合は [単位] をheightにしておく。

  • trialルーチン

    • Imageコンポーネントをひとつ配置して、「基本」タブの [名前] をfaceImageに、 [終了] を空白にする。「レイアウト」タブの [サイズ [w, h] $] を(0.5, 0.5)に、 [位置 [x, y] $] を(0.0,0.1)に設定する。

    • Textコンポーネントをひとつ配置して、以下のように設定する。最終的に3つのTextコンポーネントが配置される。

      • 「基本」タブの [名前] をtextYes、[終了] を空白にし、 [文字列] に「はい」と入力する。

      • 「書式」タブの [文字の高さ $] を0.05にする。

      • スクリーン左下に提示されるように、「レイアウト」タブの [位置 [x, y] $] を(-0.2,-0.3)に設定する。

      • textYesをコピーして、textNo、textQuestionという名前で貼り付ける。

      • textNoがスクリーン右下に提示されるように [位置 [x, y] $] を(0.2,-0.3)に設定する。 [文字列] に「いいえ」と入力する。

      • textQuestionがfaceImageの下に提示されるように [位置 [x, y] $] を(0,-0.2)に設定する。textQuestionの [文字列] は後で変更するのでとりあえずそのままでよい。

    • Keyboardコンポーネントをひとつ配置し、以下のように設定する。

      • 「基本」タブの [名前] をkey_choiceとし、 [終了] が空白となっていることを確認する。

      • 「データ」タブの [検出するキー $] を'left', 'right'にする。 [正答を記録] をチェックして、 [正答] に$correctAnsと入力する。

  • instructionルーチン(作成する)

    • フローの先頭に挿入する。

    • Textコンポーネントをひとつ配置し、「基本」タブの [名前] をtextInstに、 [終了] を空白にする。「書式」タブの [文字の高さ $] に0.05を入力する。

    • Keyboardコンポーネントをひとつ配置し、「基本」タブ [終了] を空白であることを確認する。「データ」タブの [検出するキー $] を'left','right'にし、 [記録] を「なし」にする。

  • feedbackルーチン(作成する)

    • フローのtrialルーチンの直後に挿入する。

    • Imageコンポーネントをひとつ配置して、「基本」タブの [名前] をfaceImage_2に、 [終了] を空白にする。 [サイズ [w, h] $] を(0.5, 0.5)に、 [位置 [x, y] $] を(0.0,0.1)にする。

    • Textコンポーネントをひとつ配置し、「基本」タブの [名前] をtextFeedbackに、 [終了] を空白にする。「書式」タブの [文字の高さ $] を0.08にする。faceImage_2の下に提示されるように「レイアウト」タブの [位置 [x, y] $] を(0,-0.28)に設定する。

    • Keyboardコンポーネントをひとつ配置し、「基本」タブの [終了] が空白であることを確認する。「データ」タブの [検出するキー $] を'left','right'にし、 [記録] を「なし」にする。

  • reportルーチン(作成する)

    • フローの末尾に挿入する。

    • Textコンポーネントをひとつ配置し、以下のように設定する。

      • 「基本」タブの [名前] をtextReportに、 [終了] を空白にする。

      • 「書式」タブの [文字の高さ $] に0.05を入力する。

    • Keyboardコンポーネントをひとつ配置し、「基本」タブの [終了] が空白であることを確認する。「データ」タブの [検出するキー $] を'space'にし、 [記録] を「なし」にする。

  • trialsループ(作成する)

    • trialルーチンとfeedbackルーチンを繰り返すように挿入する。

    • [繰り返し回数 $] を1にする。

  • 刺激画像

  • exp06cnd01.xlsx(条件ファイル)

    • imageFile、correctAnsの2パラメータを設定する。

    • imageFileに32種類の刺激画像のファイル名を設定する。ファイル名(FileXXXXX.png)のみでパスは入力しないこと。

    • imageFileの列でファイル名の5桁の数字の左から1桁目が1である行のcorrectAnsをleftに、それ以外の行のcorrectAnsをrightにする。これで眼鏡をかけている画像ファイルに対応するcorrectAnsがleftとなる。

  • exp06cnd02.xlsx(条件ファイル)

    • exp06cnd01.xlsxをコピーし、correctAnsの列のrightをleftに、leftをrightに書き換える。これで眼鏡をかけていない画像ファイルに対応するcorrectAnsがleftとなる。

以上で準備完了です。Imageコンポーネントの [画像] をはじめ、いくつかのTextコンポーネントの [文字列] やループの [繰り返し条件] などが未設定のまま残っています。これから、以下の作業に取り組みたいと思います。

  • Imageコンポーネントの [画像] に、条件ファイルから読み込んだ刺激画像ファイル名にフォルダ名を付け足して相対パスを完成させる式を入力する。

  • 実験実行時に実験情報ダイアログのwordからターゲット語を取得し、instructionやtrialルーチンのTextコンポーネントの [文字列] 、およびreportルーチンのtextReportで提示する教示文に組み込む。

  • 実験実行時に実験情報ダイアログのconditionから条件ファイル名の番号(01、02)を取得し、前にexp06cnd、後ろに.xlsxを結合して条件ファイル名を得る。条件ファイル名を全て入力する手間を省ける。

6.5. 文字列を結合して画像ファイルのパスや教示文を作成しよう

まず、Imageコンポーネントの [画像] プロパティを設定しましょう。 [画像] には読み込む画像ファイル名を指定します。ファイル名は条件ファイルのimageFileというパラメータから読み込まれますが、単に$imageFileと書くと画像ファイルがexp06.psyexpと同じディレクトリにあると見なされてしまいます。そこでフォルダ名のimage/をファイル名の前に補いたいのですが、$image/imageFileとか$"image/"imageFileとか書いてもエラーになります。ではどう書けばいいかと言いますと、+演算子を使います。数値と数値の間に+演算子を書けば足し算になりますが、文字列と文字列の間に+演算子を書くと両者を連結した文字列が得られます。今回の場合は、以下のように [画像] に記入すれば目的を達成できます。image/を文字列として認識させるためにシングルクォーテーションまたはダブルクォーテーションで囲むことを忘れないでください。

$'image/' + imageFile

trialsルーチンのfaceImageとfeedbackルーチンのfaceImage_2の両方の [画像] にこの式を入力してください。そして、忘れずに「繰り返し毎に更新」を設定しておきましょう。

教示文へのターゲット語の組み込みも同様の方法で実現できます。expInfo['word']という式で実験情報ダイアログから文字列を取得できるのですから、以下のような式を用いれば「これは「○○」ですか?」という文字列が得られます。

$'これは「' + expInfo['word'] + '」ですか?'

trialルーチンを開いてtextQuestionの [文字列] にこの式を入力してください。実験の実行中にはexpInfo['word']の値は変化しませんので、「繰り返し毎に更新」に設定する必要はありません。この式は少々複雑なので、+演算子の前後にスペースを入れて見易くしてみましょう。

$ 'これは「'     +      expInfo['word']      +      '」ですか?'

三つの文字列を2つの+演算して結合していることがわかります。数値演算における+演算子が5+3+8という具合に3つ以上の値に次々と適用できるのと同じことです。ただし、数値演算では5+3+8でも8+3+5でも同じですが、文字列の+演算では常に演算子の左側の文字列の最後尾に右側の文字列の先頭が結合されます。

最後の教示も同様に設定してしまいましょう。reportルーチンを開いて、textReportの [文字列] に以下の式を入力してください。 紙面の都合上2行になっていますが、入力する時は途中で改行せずに1行で入力してください。

$'「' + expInfo['word'] + '」にあてはまる画像の条件を考えて、
 実験者に口頭で答えてください。

続いてinstructionルーチンのtextInstの [文字列] ですが、ここは少々解説が必要です。目標として、以下のような複数行にわたる教示文をひとつのTextコンポーネントで表示するものとします。○○には実験情報ダイアログのwordから取得した文字列が入るものとします。

「○○」は人の顔を形容する言葉です。
提示された顏の絵が当てはまるならカーソルキーの左、
当てはまらないなら右を押してください。

○○にあたる部分をexpInfo['word']にして前後を + でつなげばよいだけのように思われるかもしれません。しかし実際に試してみると、 図6.5 のようにBuilderに「構文エラーがある」と怒られてOKボタンをクリックすることができません。

_images/string-error.png

図6.5 改行がある文と $の指定は両立しない

第2章 で述べたとおり、Textコンポーネントの [文字列] には改行を含むことができます。それなのになぜ 図6.5 はエラーになってしまうのでしょうか。この問題の鍵は、Builderが [文字列] に入力されている値をどう解釈するかにあります。 [前景色] の設定を思い出してください(第3章)。 [前景色] には$が付いていないから、redと書けばredという文字列が入力されているとBuilderは判断するのでした。一方、$redと書けば、変数redに格納された値が指定されているとBuilderは判断すると述べました。実は後者は不正確な記述で、正確には$が書かれていると、Builderは$を除いた部分がPythonの式である判断するのです。$redから$を除くとredが残り、redという式を「評価」すると、変数redに格納された値が得られるのです。ここで言う「評価」とは、式の中に+などの演算子が含まれていたらその計算をしたり、関数が含まれていたらその戻り値を計算したりといった作業を行って、最終的な式の計算結果を得ることです。この「評価」という考え方はBuilderを理解する上でとても大切です。例えば 第5章 で出てきた時刻に応じて色を変化させる式 $[t/6.0, t/6.0, t/6.0] では、t/6.0が評価されてtを6.0で割った値に置き換えられることによって、RGB値として解釈できるリストとなるのです。

これを踏まえて 図6.5 に戻ります。ここには$が入力されているのでBuilderはこれをPythonの式と見なします。Pythonの式としてこれを解釈すると、1行目の最後が文字列の途中で終わってしまっています。このような書き方はPythonの文法で許されていません。同様に2行目、3行目も文字列が適切にクォーテーションで囲まれていませんのでPythonの文法を満たしていません。これではBuilderに拒否されるのは当然です。

では目指している出力を得るにはどうすればよいでしょうか。ふたつ方法がありますが、簡単な方法を紹介しましょう。Pythonでは、シングルクォーテーションまたはダブルクォーテーションを3個連ねることにより、複数行にわたる文字列を表記することができます。例えば以下のように書くと2行に表示されます。

'''必要に応じて休憩を取ってください。
準備ができたらスペースキーを押して実験を再開してください。'''

このテクニックを使うと、textInstの [文字列] は以下のように書くことができます。

'「'+expInfo['word']+'''」は人の顔を形容する言葉です。
提示された顏の絵が当てはまるならカーソルキーの左、
当てはまらないなら右を押してください。'''

以上で [文字列] に$記号を使ってPythonの式を記述した場合でも複数行にわたる文字列を表示できました。この方法を知っていればBuilderを使う分には困ることはないと思いますが、今後さらにステップアップすることを考えるのならばもうひとつの方法も知っておくと役に立つかもしれません。「6.9.1:改行文字を使った複数行の文字列の表現(上級) 」に解説しておきますので、興味がある人は読んでください。

最後に実験情報ダイアログのconditionへ入力された値から条件ファイル名を得る問題が残っていますが、ここまでの解説を理解していればもうこれ以上の解説は不要でしょう。trialsループの設定ダイアログを開き、 [繰り返し条件] に以下の式を入力してください。これで01とだけ入力すればexp06cnd01.xlsxを指定することができます。

$'exp06cnd' + expInfo['conditionFile'] + '.xlsx'
チェックリスト
  • 複数の文字列を結合した文字列を得る式を書くことができる。

  • 条件ファイルや実験情報ダイアログから読み込んだ文字列が組み込まれた文を提示することができる。

  • Textコンポーネントの [文字列] にPythonの式を書いた時に、表示する文字列を改行させることができる。

6.6. Pythonにおける比較演算子、論理演算子、条件分岐を学ぼう

ここまでの作業でとりあえず実験を実行できるところまでたどり着きましたが、最後の難題である「判断の正誤をフィードバックする」が残っています。フィードバックの提示はfeedbackルーチンのtextFeedbackを用いて行います。trialルーチンでの判断が正しければtextFeedbackの [文字列] に「正解」、誤っていれば「不正解」と提示したいのですが、当然実験参加者が正解するか否かは実験を実行する前にはわからないので、条件ファイルでは実現できません。実はこの種の参加者の反応に応じた刺激や課題の変化はBuilderが苦手とするところで、現状のBuilderではどうしてもPythonの文法知識、Pythonコードの記述が必要になります。

さて、これから「反応が正しければ『正解』、誤っていれば『不正解』と提示する」という作業をPythonのコードへ変換するわけですが、このように条件に応じて行う処理を変更することを条件分岐と言います。条件分岐は

もしAが成り立つならばBを行う。さもなければCをおこなう。

という文で表現できます。一般にプログラミング言語では「成り立つ」ことを「真(True)である」と言い、成り立たないことを「偽(False)である」と言います。この用語を用いると、先の文は

Aが真であればBを行う。偽であればCをおこなう。

と書き直すことができます。Pythonでは、この文をif, elseという語を使って 図6.6 のように書きます。ifとelseの後ろにコロン( : )がある点と、B、Cがifやelseより「字下げ」されている(行頭に空白文字がある)点に注意してください。空白文字を何文字入れるかについてのPythonでの文法上の取り決めは少々複雑なのですが、Python Enhancement Proposals (PEP)と呼ばれるPythonの公式文書において「字下げには半角スペース4文字を用いる」ことが推奨されていますので、この文書では半角スペース4文字で統一します。第7章 で詳しく触れますが、Pythonの文法では字下げが重要な意味を持っています。

_images/if-else-statement.png

図6.6 条件分岐(if文)の書式。右は実際のコードの例です。

反応が正しければ『正解』、誤っていれば『不正解』と提示する」という目標をこのif文の形式に当てはめることができれば目的は達成されますが、どう当てはめたらよいでしょうか。この目標のままではPCにとってはまだ抽象的すぎますので、もう少し書き直してみましょう。

・反応が正しければ
↓
・「押されたキーの名前が変数correctAnsの値と一致している」が真であれば

「押されたキーの名前」をPythonのコードとして表現する方法はまだ解説していないので、とりあえず変数responseに押されたキーの名前が格納されているものとして書き換えを進めますと、以下の文が得られます。

・「押されたキーの名前が変数correctAnsの値と一致している」が真であれば
↓
・「変数responseの値が変数correctAnsの値と一致している」が真であれば

続いて「『正解』と提示する」という部分についても書き直してみましょう。提示にはTextコンポーネントを使うのですから、以下のように書き直すことができます。

・『正解』と提示する
↓
・Textコンポーネントの「文字列」に'正解'と設定する

第3章 以降の解説では、Builderのコンポーネントのプロパティ値を実行中に変更する時には変数を用いてきました。今回もこの方法が有効でしょう。feedbackMsgという変数を用いることにしましょう。

・Textコンポーネントの「文字列」に'正解'と設定する
↓
・変数feedbackMsgに'正解'を代入する

「『不正解』と提示する」は「『正解』と提示する」と同様ですので省略します。ここまで書き直すことができれば、Pythonのコードへ変換することができます。 図6.6 の右側が実際にPythonのコードに置き換えてみた結果です。 図6.6 左側と見比べて、 図6.6 左側のA、B、Cに対応する右側のコードを見てください。右側のコードの意味が何となく分かると思うのですが、ここで「なんとなく」で済ませると後で躓くのでしっかり理解しておきましょう。

まずifの後に続くresponse == correctAnsですが、responseとcorrectAnsはすでに何度も出てきているPythonの変数であり、その中に値が保持されています。両者の間にある ==という記号ですが、これは比較演算子と呼ばれる演算子です。==の前後に置かれた値を比較して、両者が一致していればTrue、一致していなければFalseという「値」を返します。TrueやFalseを「値」と言われると奇妙に感じるかも知れませんが、そういうものだと思ってください。10+5を評価すると15という値が得られるのと同様に、比較演算子を含む式を評価するとTrueやFalseという「値」が得られるのです(正確に知りたい方は「 6.9.2:TrueとFalseの「値」 」参照)。比較演算子には==の他にも 表6.1 に示すものがあります。表中のXとYが両方とも数値である場合は特に難しいことはないと思うのですが、どちらか一方に文字列やリストが含まれている場合は話が厄介です。詳しく知りたい方は「 6.9.3:文字列、シーケンスに対する比較演算子 」を読んでいただきたいのですが、慣れないうちは以下の点を守って使用することをお勧めします。

  • 文字列やシーケンス型の比較の場合は==(等しい)と!=(等しくない)以外使用しない

  • 異なる種類のデータ型の比較(数値と文字列の比較)はしない

表6.1 Pythonの比較演算子

X == Y

XとYは等しい

X != Y

XとYは等しくない

X < Y

XはYより小さい

X <= Y

XはY以下

X > Y

XはYより大きい

X >= Y

XはY以上

比較演算子は、二つ以上同時に使うこともできます。例えば以下の例ではxが1以上で5未満の時にTrue、それ以外の時はFalseになります。数値がある範囲に収まっているか否かで処理を分岐させる時に便利です。

1 <= x < 5

比較演算子について学んだついでに、もうひとつ演算子を学んでおきましょう。「刺激の位置がスクリーンの左上だった場合」といった条件で分岐させたい場合には、X座標が負の値であること、Y座標が正の値であることの二つの条件を同時に満たす必要があります。このような場合は論理演算子( 表6.2 )を用います。X座標とY座標の値がそれぞれX、Yという変数に格納されているのであれば、この条件は以下のように記述できます。

X<0 and Y>0

逆に、「刺激の位置がスクリーンの左上ではなかった場合」とうい条件を指定したい場合は、X座標が0以上、またはY座標が0以下のどちらか一方が成立すればいいのですから、以下のように記述できます。

X>=0 or Y<=0

否定演算子を使うと以下のように書くこともできます。演算子を適用する順序を指定するために( )を使用していることに注意してください。まず( )の中が評価されて、その後にnotが適用されます。

not ( X<0 and Y>0 )
表6.2 Pythonにおける論理演算子

X and Y

XかつY (論理積)

XとYがともにTrueの時にTrue

X or Y

XまたはY (論理和)

XとYのいずれかがTrueの時にTrue

not X

Xの否定

XがTrueならばFalse、FalseならばTrue

比較演算子と論理演算子についての解説はこのくらいにして、 図6.8 のBとCに対応するコードも見ておきましょう(#以下の部分はPythonによって無視されるのでコメントを書く時に用いられます)。

# Bにあたるコード
feedbackMsg = '正解'

# Cにあたるコード
feedbackMsg = '不正解'

すでに前章で代入演算子を学んだ皆さんには、もうおわかりですね。feedbackMsgという変数に表示したい文字列を代入しています。

これで参加者の反応に応じて表示するメッセージを変更するためのPythonのコードの書き方がわかりました。残された問題は、この節の解説では「変数responseに格納されているものとする」と仮定した反応キー名をどうやって取得するかです。ここでまた新たな概念が登場するので節を改めましょう。

チェックリスト
  • 条件に応じて処理を分岐させるPythonコードを書くことができる。

  • 数値の大小や一致・不一致に応じて処理を分岐させることができる。

  • 文字列の一致・不一致に応じて処理を分岐させることができる。

  • Pythonの比較演算子を6つ挙げてそれらの働きを説明することができる。

  • Pythonの論理演算子を3つ挙げてそれらの働きを説明することができる。

6.7. オブジェクトのデータ属性を利用して反応にフィードバックしよう

いよいよこの章の実験の完成が近づいてきました。反応キー名を得るコードですが、これは知っていないといくら考えてもわからないことなので、解答から始めます。key_choiceという名前のKeyboardコンポーネントから反応キー名を得るには以下のように書きます。

key_choice.keys

プログラミングの経験がない方には難しい話が続きますが、この部分を理解していないと次章以降の内容を理解できません。じっくり解説しますので、頑張ってついてきてください。

このkey_choice.keysという式ですが、Pythonの文法では名前にピリオドを含むことはできませんので、key_choiceとkeysという名前がピリオドで結ばれているはずです。key_choiceというのはルーチンに配置しているKeyboardコンポーネントと同じ名前なので。恐らくKeyboardコンポーネントと関係がある「何か」だというのは容易に想像できるのではないかと思います。このkey_choiceというのは変数で、その中にはBuilderのキーボード反応計測用オブジェクト(psychopy.event.BuilderKeyResponse:以下BuilderKeyResponse)というモノが入っています。オブジェクトとは、コンピュータ上で扱うさまざまな対象、キーボードやマウスといった物理的なものから各種ソフトウェアの動作のために用いられるデータなどをプログラミング言語上から扱いやすくするための仕組みです。

とても抽象的な概念でイメージしにくいと思いますので、具体的な例を挙げましょう。 図6.7 はwebブラウザと文書作成ソフト、フォルダ内容表示の3つのウィンドウを開いている様子を示しています。これらのウィンドウは右上のボタンをクリックしてウィンドウを閉じたり最大化、最小化したりといった操作や、ウィンドウの枠をドラッグして位置や大きさを変更する動作は共通しています。しかし、ウィンドウを動かしてしまうと今まで別ウィンドウに隠されていた部分が見えるようになるのでOSはウィンドウの描き直しを行うのですが、描き直しの方法はwebブラウザや文書作成ソフトなど、個々のウィンドウで異なるでしょう。このように、コンピュータ上で扱う対象には共通化できる部分と、固有の部分があります。この共通化できる部分を共通化するための仕組みがオブジェクトです。実は、オブジェクトという考え方はここまで解説してきたBuilderのコンポーネントにも利用されています。例えば刺激に対応するコンポーネントにはいずれも [位置n [x, y] $][サイズ [w, h] $] というプロパティがあり、これらを使ってスクリーン上のどの位置にどのくらいの大きさで描画されるかを指定することができました。 [前景色] プロパティで色を指定することもできましたが、ImageコンポーネントとGratingコンポーネントでは同じ値を [前景色] に指定してもスクリーンに描かれる刺激の色は全く異なりました ( 図6.7 )。こういった刺激間の共通点や相違点を効率よくするために、Builderの内部ではオブジェクトが使用されています。

_images/what-is-object.png

図6.7 オブジェクトの例。個々のウィンドウはそれぞれ固有の位置や大きさを持ちますが、閉じたり移動させたりといった操作方法は共通しています。これまでに扱ったBuilderの刺激にも、それぞれに共通する点や異なる点があります。

Pythonにおけるオブジェクトでは、こういったさまざまな対象を表現するために、データ属性とメソッドと呼ばれるものを用います。Builderの刺激オブジェクトの例を用いると、データ属性とは [位置 [x, y] $][サイズ [w, h] $] のように、それぞれの刺激で固有の値をとるデータのことです。メソッドについては詳しくは次章で触れますが、それぞれの刺激をスクリーンに刺激を描画する手続きのように、そのオブジェクトに対する操作をおこなうものです。それぞれのオブジェクトのデータ属性やメソッドの定義をクラスと呼び、クラスに従って生成されたオブジェクトを該当するクラスのインスタンスと呼びます。 図6.8 はデータ属性、メソッド、クラス、インスタンスの関係を示しています。Gratingクラスはグレーティング刺激を描画するためのクラスで、[位置 [x, y] $][回転角度 $][テクスチャ] に対応するPosition、Orientation、Textureといったデータ属性を持っています。また、スクリーンに描画を行うためのdrawというメソッドを持っています。グレーティング刺激をスクリーンに2個描画するために、Gratingクラスのインスタンスを2個生成して、それぞれgratingPatchとstripePatchという変数に格納しました。各インスタンスのデータ属性に値を代入する時には、gratingPatch.Position = (0,0)という具合に、変数名とデータ属性名をドット演算子( . )で結合して記述します。ドット演算子を用いることによって、どちらのインスタンスに代入するのか混乱することがありません。drawメソッドを用いて刺激を描画する時には、gratingPatch.draw( )という具合にやはりドット演算子を使って変数名とメソッド名を結合して記述します。メソッドは関数と同様に引数をとることができますので、( )がdrawの後に付きます。drawメソッドでは各インスタンスのデータ属性の値を用いて刺激の位置や波形が決定されて刺激が描画されます。

_images/class-attributes-methods.png

図6.8 データ属性とメソッド、クラスとインスタンス。データ属性の値は個々のインスタンスで異なります。メソッドを呼ぶと自分のクラスで定義されているメソッドが呼び出されるので、異なるクラス間で同名のメソッドがあっても混乱しません。

グレーティング刺激に追加して、多角形の刺激を描画するPolygonクラスを用いて三角形と五角形を1個ずつ描画するとします。PolygonクラスはGratingクラスと似ていますがGratingクラスには無いN_Verticesというデータ属性を持っています( [頂点数] に対応)。また、Gratingクラスと同様にdrawというメソッドを持っていますが、その処理内容は異なります。多角形を2個描画するのですから、Polygonクラスのインスタンスを2個生成してtriangleとpentagonという変数に格納します。triangleとpentagonのデータ属性に適切な値を設定して、drawメソッドを呼びます。triangleに格納されたPolygonを描画する時にはtrialgle.draw()と記述しますが、このように変数名とメソッド名をドット演算子で結合して記述することによって、このdraw( )はPolygonクラスのオブジェクトのdrawメソッドであることがPythonにはわかります。ですから、Gratingクラスに同名のメソッドがあってもPythonが両者を混同することはありません。

なお、ここで想定したGratingクラスやPolygonクラスおよびそのデータ属性は、実際のBuilderで使用されているものと異なります。クラスおよびデータ属性の正確な名称およびBuilderとの対応関係を「 6.9.4:BuilderのコンポーネントとPsychoPyのクラスの対応 」に記しておきますので、詳しく学びたい方はご覧ください。Builderの通常の用途ではそこまで知っておく必要はありません。

ここまで説明して、ようやくkey_choice.keysという式の意味を解説できます。key_choiceにはBuilderKeyResponseというクラスのインスタンスが格納されています。BuilderKeyResponseはキーボードの状態を記録するためのクラスで、 表6.3 に示すデータ属性を持っています。この表によると、keysには押されたキー名が保持されています。key_choiceという変数名はBuilderのtrialルーチンに配置したKeyboardコンポーネントの [名前] に対応していますから、key_choice.keysという式はtrialルーチンに配置したKeyboardコンポーネントで記録したキー名です。具体的に言えば'left'か'right'のいずれかの文字列が格納されています。ですから、Codeコンポーネントに入力したkey_choice.keys == correctAnsは実験参加者が押したキーのキー名がcorrectAnsと一致すればTrue、一致しなければFalseが得られます。

表6.3 BuilderKeyResponseクラスのデータ属性

データ属性

概要

keys

ルーチンで記録されたキー名が格納されています。キーが押されていなければ空のリスト、「最後のキー」または「最初のキー」を記録している場合は該当するキー名、「全てのキー」を記録している場合は押されたキーのキー名が順番に並んだリストが格納されています。

corr

反応が正答であれば1、誤答であれば0が格納されています。キーが押される前は0です。

rt

キーが押された時刻が格納されています。キーが押されていなければ空のリスト、「最後のキー」または「最初のキー」を記録している場合は該当するキーが押された時刻、「全てのキー」を記録している場合は各キーが押された時刻が順番に並んだリストが格納されています。

clock

Builderが時刻を計測するための時計オブジェクトのインスタンスが格納されています。直接操作すべきではありません。

これで必要な要素はすべてそろいました。Builderでexp06.psyexpを開いて、trialルーチンを開いてCodeコンポーネントを配置してください。そして [Routine終了時] に以下のコードを入力しましょう。

if key_choice.keys == correctAns:
    feedbackMsg = '正解'
else:
    feedbackMsg = '不正解'

ついにexp06.psyexpの完成です。さっそくexp06.psyexpを実行してください。実験情報ダイアログのconditionには01とだけ入力し、wordに「リニ」などの無意味語をターゲット語として入力してOKをクリックしてください。条件ファイルとしてexp06cnd01.xlsxが読み込まれて、最初の教示文にはターゲット語が埋め込まれているはずです。そして、刺激が出てきたら適当に反応して、眼鏡をかけている顔画像に対して「はい」を選択する(カーソルキーの左を押す)と正解、それ以外の顔画像に対して「はい」を選択すると不正解になることを確認しましょう。実験が終了したらもう一度実験を実行して、今度は実験情報ダイアログのconditionに02と入力してOKをクリックしてみましょう。眼鏡をかけている顔画像に「はい」を選択すると不正解、それ以外の画像に対して「はい」を選択すると正解になるはずです。

以上でこの章の解説はおしまいです。if文についてはまだまだ説明したいことがたくさんありますが、この章もずいぶん長くなってしまったので、ここで一区切りにして次の章で取り扱うことにしましょう。

チェックリスト
  • クラスとインスタンスの違いを説明することができる。

  • データ属性とは何かを説明することができる。

  • 変数xに格納されたインスタンスのデータ属性fooに値を代入したり値を参照したりするときのPythonの式を書くことができる。

  • BuilderKeyResponseのデータ属性を参照して押されたキー名を知ることができる。

6.8. 練習問題:データ属性corrで正誤を判定しよう

この章の解説では、条件ファイルとして眼鏡をかけている顔画像が正事例となるexp06cnd01.xlsxと、眼鏡をかけていない顔画像が正事例となるexp06cnd02.xlsxの二種類しか作成しませんでした。しかし、実際にexp06.psyexpを使って概念識別の実験をするためには、他の特徴が正事例となる条件ファイルを準備する必要があります。練習問題として、「眼鏡をかけていて眉が上がっている(論理積)」顔画像が正事例となる条件ファイルと、「顔が丸い、または眉毛が下がっている(論理和)」顔画像が正事例となる条件ファイルを作成してください。

もうひとつ、if文とBuilderKeyResponseの復習問題として、trialルーチンの反応が正答であったか誤答であったかに応じてfeedbackMsgに代入する文字列を変更する部分で、データ属性keysを使わずにデータ属性corrを使うようにCodeコンポーネントの内容を書き換えてください。 表6.3 に示すように、データ属性corrには反応が正答であれば1、誤答であれば0が格納されています。これはほぼ答えを言っているようなものなので、これ以上はノーヒントで挑戦してください。

6.9. この章のトピックス

6.9.1. 改行文字を使った複数行の文字列の表現(上級)

Microsoft Wordなどの文書作成アプリケーションを使ったことがある方は、この種のアプリケーションでは 図6.9 文の末尾に矢印のような記号が(しばしば本文とは異なる色で)描かれていることに気付いておられると思います。実は、アプリケーションの内部では、この「矢印」もひらがなや漢字、英数字と同じ「文字」の一種で、ここで「行が変わる」ことを表しています。文字として扱われている証拠(?)に、普通の文字と同様にBackSpaceキーやDelキーで削除できますし、削除したら前後の文が1行につながりますよね。この「行が変わる」ことを表す文字を 改行文字 と呼びます。「 3.11.5:$を含む文字列を提示する 」で「コンピュータにおいて文字は『文字コード』と呼ばれる数値で表される」と書きましたが、改行文字にも数値が割り当てられています。例えばWindowsでは0x0D0A、Linuxでは0x0Aです。

_images/newline-characters.png

図6.9 改行文字の表示例。行末の矢印のような記号が改行文字です。

Pythonを含む多くのプログラミング言語では、この改行文字をエスケープシーケンス(「3.11.5:$を含む文字列を提示する 」参照)を使って\nと表すことができます。つまり

'当てはまるならカーソルキーの左、\n当てはまらないなら右を押してください。'

と書くと、

当てはまるならカーソルキーの左、
当てはまらないなら右を押してください

のように\nの位置で改行されて出力されます。\nを使う方法を知っていると、インターネット上で誰かが書いたプログラムを参考にして勉強するときなどにきっと役に立ちますのでぜひとも覚えておきたいところです。

さて、本章の教示も\nを使って記述することができますが、一行に書くには長すぎます。このような場合、Pythonの文法には

  • 行末が \ のみで終わる場合は次の行につながっているとみなす

  • '今日は' 'いい天気' のように二つの文字列の間に空白文字しかない場合は自動的に接続して '今日はいい天気' と同じとみなす

という規則があることを利用して

'「' + expInfo['word'] + '」は人の顔を形容する言葉です。\n' \
'提示された顏の絵が当てはまるならカーソルキーの左、\n' \
'当てはまらないなら右を押してください。'

と書くことができます。\は最後の行には不要(というか書いてはいけない)点にご注意ください。\nは各行の末尾以外に置いても構わないので、

'「' + expInfo['word'] + '」は人の顔を形容する言葉です。\n提示された顏の絵が' \
'当てはまるならカーソルキーの左、\n当てはまらないなら右を押してください。 '

と書くこともできます。上の例とじっくり見比べて、同じ結果になることを確認してください。

6.9.2. TrueとFalseの「値」

Pythonでは、if文にTrueやFalse以外の値を返す式を書くことができます。その場合、式を評価した結果が0であればFalse、0以外であればTrueとして処理されます。ですから、 図6.10 上段に示した例ではいずれの場合もif文に続くx=7が実行されます。このことを積極的に利用したプログラムを書くことも可能ですが、わかりにくいのでお勧めしません。

お勧めしないと言えば、Python2におけるTrueやFalseは、あたかも通常の変数であるかのように値を代入することができます。ですから、True=0などと書いてTrueに0を代入することも可能です。ただ、このようにしてしまうとTrueを評価すると0が得られて、0はFalseとして機能するため、 図6.10 下段の例のような非常にややこしい事態が生じてしまいます。TrueやFalseへの代入は絶対に行うべきではありません。 Python3ではTrueとFalseが予約語となったため、このような代入はできなくなっています。

_images/true-false-value.png

図6.10 TrueとFalseに関する注意事項(True/Falseへの代入はPython2のみ)。

6.9.3. 文字列、シーケンスに対する比較演算子

本文では<や>=といった比較演算子を使って数値の大小を比較する方法について解説しましたが、Pythonでは文字列やシーケンス型のデータに対しても比較演算子を使用することができます。これらのデータに対して比較演算子が適用された場合は「辞書順」に従って比較が行われます。

例えばmemoryとmindという文字列を比較するとしましょう。英和辞典の順番では、1文字目から順番に比較していって、最初に異なる文字のアルファベット順でどちらが先に掲載されるかが決まります。memoryとmindでしたら1文字目はどちらもm、2文字目はeとiですから、eの方が前です。Pythonでは、辞書順で前にくる文字列ほど「小さい」と判定されますので、'memory' < 'mind'はTrueとなります。'memory' > 'mind'はFalseです。

少し注意が必要なのは、数値や漢字が文字列に含まれる場合です。半角数字はすべてのアルファベットより「小さい」と判断されます。ですから'magical number' < '7'を評価するとFalseが得られます('7'は'm'より小さいと判断される)。かな文字や漢字は文字コードに従って解釈されますので、文字コードを理解していなければ結果を予測するのは困難です。例えばUnicodeで「心」は「記」より小さい値で表されますので(それぞれ0x5fc3と0x8a18)'記憶' < '心'を評価するとFalseが得られます。筆者の個人的な意見としては、このような比較は非常にわかりにくいので可能な限り使用するべきではないと思います。

シーケンスの場合は、要素を先頭から順番に比較していきます。[7,8,2] < [7,1,5,9]という比較でしたら、最初の要素の7は同一、2番目の要素は8と1で左辺の方が大きい値ですので、左辺の方が大きいと判定されます。従って[7,8,2] < [7,1,5,9]はFalseです。シーケンスの要素に文字列が含まれている場合も、同様に個々の要素を先頭から順番に比較します。['theory', 7, 'mind'] > ['theory', 7, 'memory']でしたら最初と2番目の要素は同一、3番目の要素はmemoryよりmindの方が「大きい」のでしたからTrueが得られます。

6.9.4. BuilderのコンポーネントとPsychoPyのクラスの対応

図6.11 にBuilderのGratingコンポーネントと、それに対応するPsychoPyのクラスを示します。Gratingコンポーネントに対応するクラスはpsychopy.visual.GratingStimという名称(以下GratingStim)です。Gratingコンポーネントの各プロパティはGratingStimクラスのデータ属性と対応しています。Builderにおいて各プロパティに式や値を設定するという作業は、対応するGratingStimクラスのデータ属性にそれらを設定することと同義です。自分で実験用のPythonコードを書く場合は、GratingStimクラスのデータ属性名やその設定方法を覚えなければいけません。Builderはプロパティ設定ダイアログという形でプロパティの一覧を見て設定ができるので、コードを書く方法を覚えるよりも手軽に自分の実験を作成できる段階まで学習できます。これがBuilderを利用する最大の利点です。

_images/grating-attributes-correspondence.png

図6.11 BuilderのGratingコンポーネントのプロパティと、それに対応するPsychoPyのクラスのデータ属性。

ただし、の下の方に対応するプロパティが存在しないデータ属性があるように、BuilderではGratingStimクラスの全てのデータ属性やメソッドを利用することができません。PsychoPyの機能を最大限に活かすためにはやはりコードを書く必要があります。

表6.4 は、PolygonコンポーネントとPsychoPyのクラスの対応関係を示しています。Polygonコンポーネントの場合は、 [形状] に応じて最も効率がよいクラスをBuilderが選択します。クラスによってデータ属性が異なりますので、Polygonコンポーネントのプロパティとデータ属性の対応も選択されたクラスに応じて変化します。

Builderは、背後にあるPsychoPyのクラスやそのデータ属性についての知識がなくても使用できるように設計されています。実際、第5章 まではPsychoPyのクラスについて触れずに解説を進めてくることができました。しかし、この章の実験のように、参加者の選択に応じて刺激などが動的に変化する実験を作成するためには、残念ながら現状のBuilderではPsychoPyのクラスについて言及せざるを得ません。

表6.4 BuilderのPolygonコンポーネントに対応するPsychoPyのクラス

形状

対応するクラス

直線

psychopy.visual.Line

三角形

psychopy.visual.ShapeStim

長方形

psychopy.visual.Rect

十字

psychopy.visual.ShapeStim

psychopy.visual.ShapeStim

正多角形...

psychopy.visual.Polygon