.. title:: Pythonで心理実験 - 例題19-4 例題19-4:いっぺんにするなんて無理ですよ ============================================ **A:** さて、さっそく例題19-4を始めようか。 **B:** いきなりですな。最近ネタ振りなしにいきなり本題に入る手抜きが多くないですか? **A:** まあ読者は振りなんかいらんからさっさと本題に入れよと思ってるかも知れん。ま、実は今回のネタは :doc:`例題18-7 <18-7>` で作者が **間抜け** にも思いつかなかったブロックの順番をランダム化する話なんで、あまりネタ振りをする余地がないんだな。作者は私(A)が思いつかなかった解決方法をB君がひらめいて持ってくるという導入を考えていたみたいだが、ホレ、前回例題19-3で私が次回予告して帰っちゃっただろ。だからB君が持ってくるっていうストーリーに出来なくなっちまったんだと。 **B:** くッ、せっかくのぼくが活躍するチャンスがッッ!! **A:** 残念でした。じゃあさっさと本題に入るぞ。例題18-7ではサイモン課題っぽい実験を作ってみたわけだが、その時に「赤が出てきたら左を押す」ブロックと「赤が出てきたら右を押す」ブロックの順番が固定されていた。例題18-7からFlowの図を引っ張ってくると以下の通り。 .. figure:: img/18-7-02.png **B:** はいはい、覚えていますよ。順番固定でいいんですか?って聞いたら、順番をランダム化する方法を思いつかなかったって言われました。 **A:** その通り。で、その時はCodeコンポーネントとかを使わずに順番をランダム化するのは無理っぽいなあと思っていたんだが、後になってふと思い立った方法を試してみたらあっさりできてしまった。19-4a.zipに条件ファイルとpyexpファイルをまとめておいたのでダウンロードして展開してほしい。 + `19-4a.zip `_ **B:** 展開しましたよ。PsychoPyで開きますね。 **A:** おっ、ありがとう。さて、まずはFlowペインから見ていこうか。例題18-7では教示を表示するルーチンがinstructionRedRightとinstructionRedLeftの二つだったが、19-4aではinstructionひとつになっている。 そして、instructionルーチンとtrialルーチンのループを大きく取り囲むblocksというループが追加されている。 .. figure:: img/19-4-01.png **B:** おおお、なんだか知らないけどループが二重になっていると格好いいぞ。 **A:** さらに中身を見ていこう。trialルーチンは例題18-7から変更してない。instructionルーチンでは、条件ファイルを使って教示を差し替えるように変更している。 教示は条件によって変化する「赤い円が出てきたら…」って部分と、どちらの条件にも共通の「準備が出来たら左右どちらかのカーソルキーを押してください。」って部分をそれぞれ独立したTextコンポーネントに分けて、変更する必要がある方だけ変更するようにしている。 .. figure:: img/19-4-02.png **B:** Textの欄に$instructionって書いてあるから、条件ファイルのinstructionという見出しがついた列から教示を読むんですね。 **A:** やけに不自然な口調だな。まあその通りなんだが。そして **set every repeatにするのを忘れない事** 。 **B:** へへへ。同じ失敗は何度も繰り返しませんよ。 **A:** あとこれは今回の改良とは直接関係ないんだけど、前回の補足。結果のファイルにはinstructionルーチンのキー押しは保存する必要がない。 **B:** そりゃそうですね。 **A:** そこでinstructionルーチンのKeyboardコンポーネントの設定を確認してほしい。キー押しを保存しなくていい場合は、このようにStoreの欄をnothingにしておく。そうすると、このKeyboardコンポーネントは結果ファイルに何も出力しないので、余計な出力がなくなってデータが見やすくなる。 **B:** ははあ、なるほど。 **A:** で、blocksループの設定がこちら。繰り返し回数は1回、blocks.csvから条件を読む。例題18を卒業したなら特に問題はないでしょ。 .. figure:: img/19-4-04.png **B:** ふむふむ。じゃあblocks.csvの中身を確認して、と… なんじゃこりゃあ! .. figure:: img/19-4-05.png **A:** あー。そうか、Excelで開くと文字化けしちゃうか。 **CSVファイルを条件ファイルとして使用する場合、文字コードはUTF-8でなければならない** 。 なのでblocks.csvもUTF-8で保存しているんだが、Excelはそれを認識できないのでこのように化けてしまう。 **B:** うー。じゃあどうやって確認すればいいんですか? **A:** 手っ取り早いのはUTF-8対応のエディタを使う事だな。私が愛用しているサクラエディタで開くとこのとおり、正常に表示される。 .. figure:: img/19-4-06.png **B:** うーん、敷居が高いなあ。Windows標準のアプリで何とかならないんですか? **A:** 実は一応Windowsのメモ帳でUTF-8のファイルを開いたり保存したりできる。しかし、どうも「メモ帳 UTF-8」なんかで検索する限りメモ帳でUTF-8を使うのはいろいろよろしくなさそうなんで、他のアプリを使うのがお勧めだな。 .. figure:: img/19-4-07.png **B:** じゃあ何かおすすめしてくださいよ。 **A:** 個人的にはLibreOffice Calcだな。CalcでCSVファイルを開くと、こんな風に文字コードやら何やらを指定するダイアログが出て来る。ここでUTF-8にしておけば正常に開くことが出来る。 .. figure:: img/19-4-08.png **B:** はあ、やっとマトモに中身を確認できました。列はinstructionとblockFileの2列。条件数(行数)も2。instructionは教示の文字列ですかね。blockFileは…これは一緒に展開されたCSVファイルの名前ですかね? .. figure:: img/19-4-09.png **A:** そう。 **条件ファイル内に別の条件ファイルの名前を書ける** というのが前回見落としていたポイントだ。これがわかればもう解決したも同然。先へ進みたいところだが、ひとつだけ補足しておこう。どうしてもExcelで作業したい人向けの情報だ。 **B:** へ? Excelで出来るんですか? **A:** 話は簡単でな。 **xlsx形式で保存すれば、文字コードとかなーんにも気にせずに日本語を含む条件ファイルを作成できる** 。この例題ではExcelを持っていない人のことも考えてCSV形式で条件ファイルを作成しているが、Excelで作業したい!って人はそもそもExcelを持ってる人でしょ?多分。なら普通にxlsx形式を使えばいいのさ。 **B:** だはー。なんか騙された気分。 **A:** 誰が何をどう騙したというんだ。人聞きが悪い。ちなみに、他の人が作ったUTF-8のCSVファイルをExcelで開きたい場合は、拡張子をいったんtxtにしてテキストファイルウィザードを使って開くといいらしい。文字コードをきちんと認識してくれる。 **B:** えーっと、テキストファイルウィザード? どうやって開くんですか? **A:** 普通にExcelのメニューの[ファイル]→[開く]とたどって拡張子txtのファイルを開けばいい。 **B:** あ、ほんとだ。ファイルウィザードが開きました。 .. figure:: img/19-4-10.png **A:** ファイルを選択するダイアログで「ファイルの種類」を「すべて」や「テキストファイル」などにしないと拡張子txtのファイルは表示されないので注意してほしい。また、txtファイルをドラッグ&ドロップしてもテキストファイルウィザードは開かないので、きちんとメニューから開くこと。一度正常に開けば、後はxlsx形式に保存するなり好きなようにすればいい。さて、そろそろ本題に戻ろう。 **B:** あ、なんだかExcel講座のような気がしてきていました。 **A:** さて、blocks.csvでは教示画面で表示するテキストと、そのブロックで使用する条件ファイル名が指定されている。あとはblocks.csvで指定した条件ファイルをtrialsループで読み込ませるように指定するだけだ。trialsループの設定を開いて。 **B:** ええと、Flowペインのtrialsって書いてるところをカチカチ。 .. figure:: img/19-4-11.png **A:** OK。ここではconditionsFileの欄に、blocks.csvで条件ファイル名を指定した列の見出し、すなわち$blockFileを指定しておく。こうしておけば、trialsループが始まるたびに条件ファイルが読み込まれて、読み込んだ条件ファイルに書かれた値がtrialsループの中で使われる。当然 **この時点ではPsychoPyには読み込まれる条件ファイルがわからないので、conditionsFileの上の余白部分には No parameters set (conditionsFile not found)と書かれている** 。 **B:** なんだかエラーみたいですね。正常に読み込めているのか確認できないのは不安だなあ。 **A:** 仕方ないだろ。PsychoPyにとっちゃ実行してみないとわからないんだから。さて、例題18-7からの変更点はこれだけだから、さっそく実行してみな。 **B:** あ、じゃあさっそく。 *------------------------------ 数分経過 ------------------------------* **B:** 終わりましたよ。 **A:** んじゃ、結果ファイルを確認しておくか。まず、CSVファイルはExcelで開くとご覧のとおり悲惨な有様。これを正常に開くための方法はさっきの条件ファイルの時と同じね。 **B:** うわ、こりゃさっきよりひどいな。 .. figure:: img/19-4-12.png **A:** 面白いのはxlsxファイルを出力している場合。trialsループが繰り返された回数だけ、シートが挿入される。最初の繰り返しではtrials、以降trials1、trials2、…と後ろにつく数値が増えていく。今回は2回しか繰り返されていないのでtrialsとtrials1だけ。 .. figure:: img/19-4-13.png **B:** ふむふむ。 **A:** で、最後にblocksというシートが挿入されている。ちょっとこれはわかりやすいようにblocksループのnRepsを3に設定して実行回数を増やしてある。 .. figure:: img/19-4-14.png **B:** へ? ということは、ええと、blocksループ1回につきtrialsループは2回実行されるんだから、合計でtrialsループは合計で6回実行される…? **A:** その通り。だからこの例ではワークシートのblocksの左側にtrials5までの合計6枚のマークシートがある。注目してほしいのは、上の赤枠で囲まれたところ。"n"とついた列にはred-left.csvが使われた条件とred-right.csvが使われたtrialsがそれぞれ3回であることが示されている。で、その右の"order"という見出しから右の列には、実行されたtrialsループの何番目にその条件ファイルが適用されたかを示している。 **B:** ええと、それはつまり、red-left.csvが使われたのは0番目、3番目、5番目のtrialsということですか? **A:** 御名答。作者が疲れて来るとB君の勘が冴えわたるな(笑) **B:** え? なんですって? **A:** いやいや、こっちの話。とにかくこのシートを見れば、どのシートがどの条件に対応しているのかがわかるわけだ。 **B:** なるほど、重要ですね。…ところで気になっていることがあるんですが。 **A:** ん? 何? **B:** Excelのワークシートって何枚まで挿入できるんですか? 長丁場の実験だとあっという間に数十ブロックになってしまうと思うんですが。 **A:** あー。私も良く知らんのだけど、どうもExcelが使用できるメモリに依存するらしいよ。ま、そもそも何十ブロックにもなってしまうような場合は実験計画を見直すべきだと思うがね。 **B:** それはそうかも知れませんが…。 **A:** 昔ひとつのExcelファイルに40枚くらいシートを作ったことがあったな。目的のシートを探しにくいったらありゃしない。 **B:** あのー、ワークシートの話はもういいんですが、もうひとつ気になることが。 **A:** なんだよ一体。 **B:** いや、今回の19-4aですか。これは毎回「赤=左キー」が先になるか「赤=右キー」が先になるかはランダムに決まるんですよね。論文でよく見かける「参加者の半数は『赤=左キー』から、残り半数は『赤=右キー』から」みたいな統制はどうしたらいいんですかね? **A:** ふむ。なかなかいい点を突いてきたな。ランダムになるのを避けるだけならblocksのループをsequentialにすればいい。blocks.csvに書かれた順番に固定される。だが… **B:** その方法だったら結局2種類の実験を作らないといけなくて、例題18-7の時からほとんど進歩がないですよね。 **A:** そう、それよ。確かにB君の言うとおりだな。んー、どうするかな。ちょっと待ってよ。 *------------------------------ 数分経過 ------------------------------* **A:** よいしょ。こんなもんかな。19-4b.zipとしてまとめたので読者の皆さんはダウンロードして展開してください。 + `19-4b.zip `_ **B:** んじゃ、実行してみますよ。…っと、最初のinfoのダイアログにblock fileとかいう項目が追加されていますが、これは何を入力したらいいんですか? .. figure:: img/19-4-15.png **A:** こらこら、勝手に始めるな。19-4bは基本的に19-4aと同じなんだが、infoのダイアログでどの条件ファイルを使用するか指定できるようにしたんだ。ダイアログの括弧の中に(L.csv or R.csv)って書いてあるだろ? 19-4b.zipを展開したディレクトリを確認してほしいんだが、blocks.csvが無くなって代わりにL.csvとR.csvという条件ファイルが追加されている。L.csvとR.csvは基本的にblocks.csvと同じ内容なんだが、L.csvは「赤=左キー」条件が1行目に、R.csvは「赤=右キー」条件が1行目に書かれている。これらの条件ファイルのどちらか一方を指定してsequentialで繰り返す設定で読み込めば、先に実施される条件を選べるわけだ。 **B:** じゃあこのダイアログにいちいちL.csvとかR.csvとか条件ファイル名を入力しなきゃいけないんですか? プルダウンメニューでぱぱっと選べたらいいのに。 **A:** ん。実はその点に触れなきゃならんのだが、それは最後に。まず19-4aからの変更点を確認していこう。まずFlowペインのblocksループ。ここはループの種類をsequentialに変更して、conditionsFileの値はinfoダイアログから引っ張ってくるように変更してある。 .. figure:: img/19-4-16.png **B:** なんだかconditionsFileの値が変なんですが。$expInfo['...e(L.csv or R.csv)']って、[ ]の中は、infoダイアログに表示されている項目名をそのまま書くんでしたよね( :doc:`例題19-2 <19-2>` など参照)。 **A:** うん。実際、例題19-4bを作成したときにはこんな風にちゃんと入力してあったんだが、保存した実験を後で開いてから確認するとこんな風に省略表示されるみたいだね。もちろん、省略表示されていてもPsychoPyには正しく認識されているので大丈夫。 .. figure:: img/19-4-17.png **B:** ふむふむ、気が利いているような、余計なお世話なような。 **A:** 個人的には勝手に省略してくれんなよ、って思うけどね。で、後はExperiment Settingsのダイアログを開いてinfoダイアログに"block file (L.csv or R.csv)"という項目を追加するだけなんだが、ここでちょっと問題がある。さっきB君が指摘した点だ。B君、このExperiment Settingsのダイアログ、 :doc:`例題18-4 <18-4>` で紹介したものと違うんだけど、どこが違うかわかるか? .. figure:: img/19-4-18.png **B:** えーっと、ああ! Experiment infoの欄が変わってますね。例題18-4の図のExperiment infoはpythonのdictオブジェクトを直接入力する形になっていますが、こっちのExperiment infoはなんか格好いい! **A:** 格好いいってなんだよ。ちょっとバージョンいくつから採用されたか自信がないんだが、公式サイトのChangeLogを確認する限りどうやら1.75.00でExperiment Settingsのダイアログが変更されて、直接dictオブジェクトを入力しなくてもいいようになったんだ。Fieldに項目名を入力し、デフォルト値が必要ならDefaultに入力しておく。項目を追加したい場合は右の + ボタンを押し、削除したい場合は - のボタンを押す。 .. figure:: img/19-4-19.png **B:** へえ、いいじゃないですか。 **A:** Builderは出来る限りpythonの文法を知らない人でも使えるようにされるべきで、私もこれは望ましい方向への進化だと思う。ただ、デフォルト値にpythonのリストを入力してもただの文字列と認識されるようになってしまったんだ。1.75.00以前の形式、というかpythonスクリプトでpsychopy.gui.DlgFromDictを直接呼び出す方法なら、デフォルト値としてリストを与えるとプルダウンリストが表示される。例えばこのスクリプトを実行してみよう。 :: import psychopy.gui params = {'block file':['L.csv', 'R.csv'], 'participant':'', 'session':'001'} dlg = psychopy.gui.DlgFromDict(params) .. figure:: img/19-4-20.png **B:** そうそう、求めていたのはこういうものですよ。 **A:** さて、素朴に考えればBuilder上ではExperiment SettingsのExperiment infoの欄に次のように入力すれば同じ結果になりそうな気がする。 .. figure:: img/19-4-21.png **B:** まあ、そうでしょうね。 **A:** ところが実行してみるとわかるように、これではうまくいかない。['L.csv', 'R.csv']というリストではなく、"['L.csv', 'R.csv']"という文字列だと解釈されてしまうんだな。だからこんな風にプルダウンリストではなくて文字列を入力するエディットボックスが表示されてしまう。 .. figure:: img/19-4-22.png **B:** うむむ。なんとかならないんですか。 **A:** まあTextコンポーネントなどのように「先頭に$が付いていればpythonの文として解釈、付いていなければ文字列として解釈」と解釈するようにパッチを当てることはそんなに難しくないと思うが…。どうだろうな。そういう解決策が「pythonの文法を知らなくても使える」という方向性に一致するのかどうか。 **B:** なるほど。一筋縄ではいかないんですね。 **A:** だね。いやあ、それにしても「PsychoPyのいいところは開発が活発なところだ」って前に書いたけど、今回は開発が活発なことの負の側というか何と言うかが出てしまった形だな。どんどん変更されていってしまうので、数か月前に書いた解説があっという間に無効になってしまう。その点VisionEggはよく言えば「枯れて」いて、数年前に書いた解説が今でもそのまま使える。 **B:** …。 **A:** 個人で使用している分には「バージョンアップしてでも使いたい!」と思わせる機能が出てくるまでひとつのバージョンを使い続ければいいんだが、新規ユーザーは普通最新のバージョンをダウンロードするから、解説記事は最新版をフォローし続ける必要がある。 **B:** ふうん。解説書くのも大変なんですねえ。 **?:** **まっ、テキトーにやってるんで他のことで忙しかったら放ったらかしですけどねー** **B:** な、なんだ、誰だ今の。 **A:** そんなわけで今回はここまで。ではまた。