SlideShare a Scribd company logo
1 of 82
Download to read offline
PsychoPy Builder
ステップアップ
視覚実験プログラミングワークショップ2018
講師:十河宏行 内藤智之
このセッションの目標
• PsychoPy Builderが出力するコードの流れを理解する
• マウスで任意の刺激をクリックする
• 実行時に無作為にパラメータを決める
• 音声刺激を再生する
2
PsychoPy Builder
trials (25x4) random
trial
• 実験の流れをルーチンとフローで
表現する。
• ルーチンは時刻、キー押し、マウ
スクリックなどで終了する。
• ループでは繰り返し毎にxlsxやCSV
の条件ファイルから値を取りだす
ことが出来る。
3
trials (25x4) random
trial
• 条件を満たした時にクリックした
ら終了する
• 参加者の反応に応じて刺激を変更
する
• フローを分岐させる
• 実行時に無作為に値を決定する
などの処理は、RatingScaleコンポーネントや
StaircaseHandlerなどで特別にサポートされて
いる場合を除いてBuilderでは難しい。
Codeコンポーネントを使って
Pythonのコードを挿入
4
知っておきたいPythonの文法(1)
• 変数名
• 大文字と小文字は区別される
• ドット( . )を含んではいけない
• 制御構文
• 条件分岐: if - else文
• 繰り返し: while – else文とfor – else文
• 繰り返しの中断:continue文とbreak文
• 複文:インデントで示す
5
知っておきたいPythonの文法(2)
• 比較演算子
• x == y:xとyは等しい
• x != y:xとyは等しくない
• x is y:xとyは同一 (Noneと比較するときはis)
• あとは>, <, >=, <=など
• 論理演算子
• x or y:xまたはy
• x and y:xかつy
• not x:xではない
6
知っておきたいPythonの文法(3)
• シーケンス
• x[index]:要素の取り出し(最初の要素は0)
• x[start:stop:step]:スライス(matlabと違うので注意)
• x in ["dog", "cat"] :要素が含まれているか
• dict
• x[key]:要素の取り出し(keyはimmutableなオブジェクト)
• x{key1:val1, key2:val2}:dictオブジェクトの定義
• 他のプログラミング言語ではハッシュ、連想配列と呼ばれることも
7
知っておきたいPythonの文法(4)
• クラス
• x=X():Xというクラスのオブジェクトを作成してxに代入
• x.size:オブジェクトxのsizeという属性(attribute)
• x.draw():オブジェクトxのdraw()というメソッド
• モジュール
• import mod:modというモジュールを読み込む
• mod.obj:modモジュールのobjというオブジェクト
8
for word in ["dog", "cat"]:
stim.text = word
while clock.getTime() < 1.0:
keys = event.getKeys()
if "space" in keys:
break
stim.draw()
win.flip()
forによる
繰り返し
in演算子
breakで繰り返しを
中断
これはfor文の一部でin演算子
ではないので注意
比較演算子
オブジェクトの
メソッドを実行
モジュールの
関数Whileによる
繰り返し
if文による分岐
字下げによる
複文
9
Builderが出力するコードを理解する
trials (25x4) random
trial
CSVやxlsx形式のファイルからパラメータを行単位で読み取り、
指定された方法(sequential, random, …)で繰り返す。
内部ではfor文で実現されている。
#
# 実験の初期化処理
#
for thisTrial in trials:
#
# trialルーチンの処理
#
#
# 実験の終了処理
#
10
trials (25x4) random
trial
# 実験の初期化処理
for thisTrial in trials:
# trialルーチンの初期化処理
while continueRoutine and …:
#
# 刺激の更新・入力の処理など
#
# trialルーチンの終了処理
#
# 実験の終了処理
ルーチンの内部では、キーボードやマウスの入力処理、刺激パラメータの
更新、画面の描画などを行っている。
内部ではwhile文で実現されており、時間による終了、キー押しによる終了
など、終了方法によってwhile文の条件式は異なる。ただしcontinueRoutine
という変数は常に存在していて、この変数をFalseにすれば必ずルーチンは
終了する。
11
practices
practice
trials
trial
# 実験の初期化処理
for thisPractice in practices:
# practiceルーチンの初期化処理
while continueRoutine and …:
#
# 刺激の更新・入力の処理など
#
# practiceルーチンの終了処理
for thisTrial in trials:
# trialルーチンの初期化処理
while continueRoutine and …:
#
# 刺激の更新・入力の処理など
#
# trialルーチンの終了処理
#
# 実験の終了処理
フローに複数のループが並ぶときには、
for文(とその中のルーチンに対応する
while文)が並べられる。
12
practice
trials
trial
# 実験の初期化処理
for thisPractice in practices:
# practiceルーチンの初期化処理
while continueRoutine and …:
#
# 刺激の更新・入力の処理など
#
# practiceルーチンの終了処理
# trialルーチンの初期化処理
while continueRoutine and …:
#
# 刺激の更新・入力の処理など
#
# trialルーチンの終了処理
#
# 実験の終了処理
一つのループ内に複数のルーチンが並ぶ
ときには、ループに対応するfor文の中に
while文が並べられる。
13
Codeコンポーネントは以下の5つの
パラメータを持っている。
• 実験開始時
• Routine開始時
• フレーム毎
• Routine終了時
• 実験終了時
Codeコンポーネント
14
practice
trials
trial
実験
開始時
実験
終了時
Routine
終了時
Routine
開始時
フレーム
毎
# 実験の初期化処理
for thisPractice in practices:
# practiceルーチンの初期化処理
while continueRoutine and …:
#
# 刺激の更新・入力の処理など
#
# practiceルーチンの終了処理
# trialルーチンの初期化処理
while continueRoutine and …:
# 刺激の更新・入力の処理など
#
# trialルーチンの終了処理
# 実験の終了処理
「実験開始時」のコード
「Routine開始時」のコード
「フレーム毎」のコード
「Routine終了時」のコード
「実験終了時」のコード
上図のtrialルーチンにCodeコンポーネント
を置くと、各パラメータに記入したコード
はこれらの位置に挿入される。
15
予約語
PsychoPy Builderはユーザーが作った
刺激やパラメータの名前をそのまま
Pythonに翻訳するので、Pythonの正
常な動作のために確保されている語
(予約語)を使うことはできない。
Pythonのキーワードの他にもBuilder
の動作のために予約されている語が
ある。詳しくは「PsychoPy Builderで
作る心理学実験」付録参照。
16
最近のBuilderであれば、予約語を
使おうとすると警告が表示される。
自分が使おうとしている語が予約
語か自信がなければ適当なコン
ポーネントを置いて「名前」の欄
に入力してみるとよい。
警告
OKをクリック
できない
17
バージョンによっては警告が
表示されないのでOKボタンで
判断する必要があります
予約語で注意が必要なのは、条件
ファイルの列名に誤って予約語を
使ってしまうケースである。
Builderは警告を発しないので、謎
のバグが生じる原因となる。
予約語かどうか気にするのが煩わ
しい場合は必ず前に p_ と付ける
などの工夫をすればよい。
filenameは
予約語!
18
例題:アイオワギャンブリング課題
75000円 77500円
-2500円
5000円カードを選んでください
参加者が4枚のカードデッキから1枚を選んで報酬を受け取ったり罰金を支払ったりする。100枚を
選んだ時点で手持ちの金額を大きくするように教示する。
デッキごとに報酬および罰金が決められており、報酬は低いが罰金も低くGoodと、報酬は高いが
高額の罰金も科せられるBadがある。
19
75000円 77500円
-2500円
5000円カードを選んでください
Builderで実験を作り始めるときのポイントの一つがルーチンの分割である。
画面変化の前後で共通部分が全くないなら迷うことはないが、今回の例の
ように一部共通部分がある場合は判断が難しい。
カードは共通
所持金は共通
フィードバック
画面のみ
選択画面のみ
20
もうひとつのポイントは、どのパラメータを条件ファイルから読み込んで、
どれをpsyexpファイル内に組み込むかである。
原則として、試行毎に変化するものは試行の条件ファイルへ、ブロック間
で変化するものはブロックの条件ファイルへ、一回の実験プログラム実行
中に変化しないものはpsyexpファイルに組み込む。
77500円
-2500円
5000円
罰金は試行毎に変化する
→条件ファイルで定義
報酬はデッキごとに固定
→実行中は変化しない
→pyexpファイル内で定義
21
Builderでは難しいこと
• カードを選択する際に、カード以外のクリックは無視する。
• 参加者の選択したカードの色を変更する。
• 参加者の選択したカードの上に報酬と罰金の額を表示する。
• 参加者の選択に応じて現在の所持金を更新する。
• 実験実行の度にGood、Badを各デッキに割り振る。
• 実験情報ダイアログから設定するようにはできるが、面倒だし、入力を間違える
かもしれないし、参加者に見られるかもしれない。
22
とりあえず作ってみた。
trialとfeedbackの
二つのルーチンで構成
操作はマウスで行う
文字列にはとりあえず
適当な値を入れておく
23
とりあえず作ってみた。
罰金の金額のみを
条件ファイルで定義
とりあえず完成するまでは
20試行でいいや
どうやってこれらを4つの
デッキに割り振るかは…
あとで考えよう
24
Step1:
カードをクリックした時にルーチンを終了
75000円
カードを選んでください
今のままだとどこをクリックしても
trialルーチンが終わっちゃうんだよね
こりゃなんとかしないと
実は次期リリース予定の1.90では
clickable objectがサポートされるの
で、Codeコンポーネントを使わず
に出来るようになると思われます。
25
for thisTrial in trials:
# trialルーチンの初期化処理
while continueRoutine and …:
#
# 刺激の更新・入力の処理など
#
# trialルーチンの終了処理
「Routine開始時」のコード
「フレーム毎」のコード
「Routine終了時」のコード
Mouseコンポーネント任せでは
ダメなので自分でコードを書く。
• 刺激表示されている間ずっと
クリックされているかを確認
しないといけない。
• カード上でクリックしたこと
を確認したらtrialルーチンを
終了させる。
trialルーチンの「フレーム毎」
へコードを挿入すればいい!
ココ!
26
• mouseの「クリックで終了」のチェックを外す。
if t>1:
for card in [card_A, card_B, card_C, card_D]:
if mouse.isPressedIn(card, [0,]):
continueRoutine = False
break
trialルーチン
• codeコンポーネントを追加し、名前をcode_trialとする。
• code_trialの「フレーム毎」に以下のコードを挿入。
27
作業しましょう!
if t>1:
for card in [card_A, card_B, card_C, card_D]:
if mouse.isPressedIn(card, [0,]):
continueRoutine = False
break
trialルーチン開始時に参加者がマウスのボタンを押しちゃっている
可能性があるので、ルーチン開始1秒後から判定を行いたい。
ルーチン開始からの時刻は予約された内部変数tに格納されている
のでt>1の時に判定を行う。
28
if t>1:
for card in [card_A, card_B, card_C, card_D]:
if mouse.isPressedIn(card, [0,]):
continueRoutine = False
break
for文を使って、card_Aからcard_Dまで順番に調べる。ルーチンに
置いた刺激コンポーネントは(原則)その名前の変数に格納され
ている。
刺激内にカーソルが置かれている状態でマウスのボタンが押され
ているかはmouseオブジェクトのisPressedIn()で判定できる。
29
if t>1:
for card in [card_A, card_B, card_C, card_D]:
if mouse.isPressedIn(card, [0,]):
continueRoutine = False
break
予約された変数continueRoutineをFalseにすれば、ルーチン内の残
りの処理を行った後にルーチン終了処理に入る。直ちに終了する
必要がある場合はbreakも使える。 →「PsychoPy Builderで作る心理学実験」11章
ここのbreak文はカードを特定したらそれ以上for文を継続せずに次の
処理へ進むためです。breakを削除したら次のstepでどうなってしま
うか考えるとよい勉強になると思います。
30
for thisTrial in trials:
# trialルーチンの初期化処理
while continueRoutine and …:
#
# 刺激の更新・入力の処理など
#
if t>1:
for card in [card_A, card_B, card_C, card_D]:
if mouse.isPressedIn(card, [0,]):
continueRoutine = False
break
# trialルーチンの終了処理
このように埋め込まれるというイメージを持とう。
31
Step2:報酬と罰金の額の位置を動かす
どのカードがクリックされたか判定
できたんだから、報酬と罰金の額を
カードの上に表示できるはずだよね。
77500円
-2500円
5000円
カードの色も変えないといけないん
だけど欲張らずに一歩ずつ。
32
• クリックしたときのマウスの
座標は調べることが出来るけ
ど、そこから報酬・罰金額の
テキスト座標を得るのは面倒
くさいよね。
• ていうか、カードの上に表示
するんだから選択したカード
のx座標に一致させればいい
んじゃないの?
75000円
カードを選んでください
33
trialルーチン
feedbackルーチン
• 先ほど追加したコードのbreakの前に以下のコードを追加。
selected_card_xpos = card.pos[0]
• text_rewardのx座標をselected_card_xposにして「繰り返し毎に更新」にする。
• text_penaltyのx座標をselected_card_xposにして「繰り返し毎に更新」にする。
34
作業しましょう!
selected_card_xpos = card.pos[0]
変数cardには(for文とif文によって)card_A, card_B, …のうちクリック
されたものが入っている。視覚刺激オブジェクトの座標は属性posに
格納されている。[0]は座標の第1要素、すなわちX座標を取り出す。
trialルーチンで設定された変数は後続のfeedbackルーチンからもアク
セスできるので、 text_rewardおよびtext_penaltyで利用できる。
 Builderにおける名前は実験全体で参照できる(global)。
異なるルーチンに同じ名前の刺激を配置できないのは
これが原因。
35
Step3:
選択されたカードの色を変える
77500円
-2500円
5000円
選択されたカードは分かってるんだ
から簡単だろ、って思っていたけど、
よく考えたら色を変えるカードは
feedbackルーチンにあるんだから、
trialsルーチンとfeedbackルーチンの
間で対応をとらなきゃいけないじゃ
ん!
36
A) trialsとfeedbackにルーチンを分けたのが
失敗だった。ルーチンひとつで済むよう
に作り替えよう
…って面倒くさいからヤダ!
B) カードに順番に0, 1, 2, 3と番号を付けて、
その番号で対応付けたらどうかな?
→できれば新しい要素を導入せずに済ま
せたいな…
C) そうだ、さっきselected_card_xposってい
う変数に選択されたカードのX座標を代
入したんだから、feedbackルーチンでこ
の座標を含むカードを探せばいいんじゃ
ないの?
77500円
-2500円
5000円
75000円
カードを選んでください
selected_card_xpos
37
feedbackルーチン
• Codeコンポーネントを追加し、名前をcode_fbにする。
• code_fbの「ルーチン開始前」に以下のコードを追加する。
for card in [card_A_fb, card_B_fb, card_C_fb, card_D_fb]:
if card.contains([selected_card_xpos,0]):
card.fillColor='black'
else:
card.fillColor='white'
38
作業しましょう!
for card in [card_A_fb, card_B_fb, card_C_fb, card_D_fb]:
if card.contains([selected_card_xpos,0]):
card.fillColor='black'
else:
card.fillColor='white'
for文を使ってcard_A_fbからcard_D_fbを順番に調べる。視覚刺激の
contains()というメソッドに座標を渡すと、その座標が刺激内に含
まれるか判定することが出来る。
塗りつぶし色を変えるには属性fillColorに値を代入すればよい。
 古いバージョンのPsychoPyではsetFillColor()メソッドを使用する必要がある。
「心理学実験プログラミング: Python/PsychoPyによる実験作成・データ処理」参照。
39
for card in [card_A_fb, card_B_fb, card_C_fb, card_D_fb]:
if card.contains([selected_card_xpos,0]):
card.fillColor='black'
else:
card.fillColor='white'
試行毎に選択するカードは変わるので、選ばれたカードを黒くす
るだけではなく、選ばれなかったカードを白くする必要がある。
これは忘れがちなので気を付ける必要がある。
40
この赤文字で示した2行を削除して実行すると
どうなるか試してみるとよいでしょう。
41
フロアからの質問
カードのX座標がselected_card_xposか調べるには
card.contains([selected_card_xpos,0])
より
card.pos[0] == selected_card_xpos
の方が良いのでは?
ご指摘の通りです。
ただcontains()はとても便利なメソッドなので、紹介
も兼ねて使いました。
Step4:
デッキにGood, Badを割り振り報酬を表示する
77500円
-2500円
5000円
GoodGood BadBad
次は金額を更新したいけど、その為
にはデッキへのGood, Badの割り当て
が済んでいないといけないな…
今まで何も考えていなかったツケが
わまってきたぞ
42
• 結果を出力する時にわかりやすいから、
‘Good1’, ‘Good2’, ‘Bad1’, ‘Bad2’という文字
列で管理しよう。
• 実験実行中に変化しないのだからCode
コンポーネントの「実験開始時」で定義
しよう。
• shuffle()を使えばデッキへの割り当てを
無作為化出来るな
[‘Good1’, ‘Good2’,
‘Bad1’, ‘Bad2’]
shuffle()
[‘Good1’, ‘Bad2’,
‘Bad1’, ‘Good2’]
43
• デッキの割当リストとカードのリストを
どう対応づけるかなあ。
• さっき「番号付けはイヤ」って考えたば
かりだけど、やっぱり番号が無難かなあ。
• あまり他の言語にない文法は使いたくな
かったけど、文が増えすぎるのも嫌だな
あ。仕方がない、enumerate()を使おう。
[‘Good1’, ‘Good2’,
‘Bad1’, ‘Bad2’]
???
[card_A, card_B,
card_C, card_D]
44
trialルーチン
• code_trialの「実験開始前」に以下のコードを追加する。
deck_list = ['Good1','Good2','Bad1','Bad2']
reward_dict = {'Good1':5000,'Good2':5000,'Bad1':10000,'Bad2':10000}
shuffle(deck_list)
• code_trialの「フレーム毎」のコードを赤字のように変更する。
if t>1:
for id, card in enumerate([card_A, card_B, card_C, card_D]):
if mouse.isPressedIn(card,[0,]):
continueRoutine = False
selected_card_xpos = card.pos[0]
selected_card_id = id
break
まだ終わりじゃないよ
45
作業しましょう!
deck_list = ['Good1','Good2','Bad1','Bad2']
reward_dict = {'Good1':5000,'Good2':5000,'Bad1':10000,'Bad2':10000}
shuffle(deck_list)
2行目はdictオブジェクト。reward_dict[‘Good1’]とすると5000が得
られる。
3行目のshuffle()は引数に渡されたリストを無作為に並べ替える。
shuffled_list = shuffle(deck_list)とするとshuffled_listはNoneとなる
(よくある間違い)。
実は番号づけせずに解決しようとしていた名残です。
番号づけするならdictを使わない方法もあります。
46
if t>1:
for id, card in enumerate([card_A, card_B, card_C, card_D]):
if mouse.isPressedIn(card,[0,]):
continueRoutine = False
selected_card_xpos = card.pos[0]
selected_card_id = id
break
enumerate()は 最初に(0, card_A), 続いて(1, card_B),… という具合に要素と
そのインデックスのペアを返してくれるジェネレーターというオブジェ
クトを返す。この機能がない言語も多いので例題として使いたくなかっ
たが今回のようなケースではとても便利なのも事実。
enumerate()で得られたインデックスを保持しておけば、何番目のデッキ
が選ばれたのかが直ちにわかる。
47
feedbackルーチン
• code_fbの「ルーチン開始前」に以下のコードを追加する。
reward = reward_dict[deck_list[selected_card_id]]
text_reward.text = u'+{}円'.format(reward)
これでStep4は完成
解説も一気に
しちゃいましょう
selected_card_idをインデックスとして、deck_listからそのデッキ
を表す文字列(‘Good1’など)を得る。この文字列をキーとして用
いるとreward_dictから罰金額を取り出せる。
罰金額は整数なので、format()を用いて”+5000円”といった表示用
文字列を得る。
 format()については「心理学実験プログラミング: Python/PsychoPy
による実験作成・データ処理」第1章参照。
 Cのような%を使った埋め込みも一応出来る(将来はなくなる?)。
48
作業しましょう!
49
フロアからの質問
dictオブジェクトを使うよりリストなどを使う方が簡単
じゃないですか?
dictはPsychoPyの使い方を学ぶ上でぜひ覚えておきたい
データ型ですが、プログラミング言語によってはdictに
相当するものがないので、今回の例ではぜひともdictの
使用例(特に{ }を使った初期化)を組み込みたいと
思っていました。
ちょっと使い方が強引だったかも知れませんね。
Step5:
罰金の額を条件ファイルから得る
77500円
-2500円
5000円
GoodGood BadBad
罰金額は条件ファイルから得ないと
いけないけど、それってどうすれば
いいのかな。
選択されたデッキ→デッキへのGood,
Badの割り当て→罰金額と対応づけて
いかないといけないぞ
50
• カードと罰金の対応は結局のところ報酬
の対応と同じことだよな。
• 条件ファイルでparam01という列の値は
Builderのコンポーネントで$param01と書
いてアクセスできるんだから、param01
という変数に格納されているはず。
• 問題は報酬ではdictオブジェクトを使っ
て対応させたのをどう解決するかだが…
param01 Param02
1 blue left
2 green left
3 red left
$param01色
変数param01
51
作業しましょう!
feedbackでroutine開始時に追加
feedbackルーチン
• code_fbの「ルーチン開始時」に以下のコードを追加する。
if deck_list[selected_card_id] == 'Good1':
penalty = Good1_Penalty
elif deck_list[selected_card_id] == 'Good2':
penalty = Good2_Penalty
elif deck_list[selected_card_id] == 'Bad1':
penalty = Bad1_Penalty
else:
penalty = Bad2_Penalty
text_penalty.text = u'{}円'.format(penalty)
52
if deck_list[selected_card_id] == 'Good1':
penalty = Good1_Penalty
elif deck_list[selected_card_id] == 'Good2':
penalty = Good2_Penalty
elif deck_list[selected_card_id] == 'Bad1':
penalty = Bad1_Penalty
else:
penalty = Bad2_Penalty
text_penalty.text = u'{}円'.format(penalty)
条件ファイルの列名がそのまま変数名になることを知っていれば、
あとはここまでのテクニックの応用である。報酬の時と同様に
dictオブジェクトを作ってもよいが、ここではif文で解決した。
53
for thisTrial in trials:
currentLoop = trials
# abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb)
if thisTrial != None:
for paramName in thisTrial:
exec('{} = thisTrial[paramName]'.format(paramName))
<上級向け>
上記コードはBuilderが出力するPythonスクリプトのループ開始部
である。
fooというループのbarというパラメータはthisFooというオブジェ
クトにbarというキーを与えてアクセスできる(thisFoo[‘bar’]) 。
実行時にexec()を用いてbar = thisFoo[‘bar’]を評価してbarという変
数名でアクセスできるようにしている。
54
Step6:
現在の所持金を更新する
77500円
-2500円
5000円
GoodGood BadBad
ここまでのことが出来ていればこれ
は難しくないよね。
一気に行くぞ。
55
trialルーチン
• Code_trialの「実験開始時」に以下のコードを追加する。
cash_pile = 100000
feedbackルーチン
• Code_fbの「ルーチン開始時」に以下のコードを追加する。
cash_pile += reward + penalty
• Text_cashを$u‘{}円’.format(cash_pile)にして繰り返し毎に更新にする。
• Text_cash_fbを$u‘{}円’.format(cash_pile)にして繰り返し毎に更新にする。
56
作業しましょう!
75000円
-2500円
5000円
75000円 77500円
金額が更新されない
この時点で
更新される
あれれれ、楽勝だと思ったのに変だぞ。
カードを選んだ時点で更新されずに次の試行に
進んでから更新される。
57
text_cash_fbを
code_fbより下へ
コンポーネントはルーチンに並べられた順番に実行される。
code_fbで更新されたcash_pileの値をtext_cah_fbに表示するためには
code_fbより下に置く必要がある。
code_trialのルーチン終了時にしておけば…
58
作業しましょう!
#------Prepare to start Routine "feedback"-------
t = 0
feedbackClock.reset() # clock
frameN = -1
# update component parameters for each repeat
text_reward.setPos([selected_card_xpos, 0.15])
text_penalty.setPos([selected_card_xpos, 0.1])
text_cash_fb.setText(u'{}円'.format(cash_pile))
# setup some python lists for storing info about the mouse_fb
for card in [card_A_fb, card_B_fb, card_C_fb, card_D_fb]:
if card.contains([selected_card_xpos,0]):
card.fillColor='black'
else:
card.fillColor='white‘
# (中略)
cash_pile += reward + penalty
表示する
金額のセット
金額の更新
Codeコンポーネント
の「実験開始時」
Codeコンポーネントより上に
配置されたコンポーネント
<上級向け>text_cach_fbの位置を修正する前の状態で出力されるコードはこのようになっている。
59
Step7:
試行毎のデータを保存する
cash pile deck reward penalty
1 77500 Good1 5000 -2500
2 87500 Bad2 10000 0
3 92500 Good2 5000 0
これでとりあえず課題が出来たから
次はデータ保存を考えよう。
まずは各試行での所持金額が欲しい
よね。あとは選んだデッキとか…
60
• これはもう知っているかどうかの勝負。
TrialsHandler.addData()というメソッドで
ループにデータを追加できる。
• Builderでループに付けた名前がそのまま
TrialsHandlerオブジェクトの変数名とな
るので、fooループにデータを追加する
ならfoo.addData()と書く。
• addData(‘name’, value)でnameという列名
でvalueという値を追加できる。
addData('deck', 'Good2')
cash pile deck reward
1 77500 Good1 5000
2 87500 Bad2 10000
3 92500 Good2 5000
61
feedbackルーチン
• code_fbの「ルーチン終了時」に以下のコードを追加する。
trials.addData('deck', deck_list[selected_card_id])
trials.addData('deck id', selected_card_id)
trials.addData('reward', reward)
trials.addData('penalty', penalty)
trials.addData('cash pile', cash_pile)
「ルーチン終了時」でなくとも保存したい変数の値が確定した時点
でaddData()してもかまわないが、この例ではループの最後にあたる
feedbackルーチンの終了時に実行した。
62
作業しましょう!
Step8:
実験中に変更しないパラメータを保存する
どのデッキがGoodだったかとか、
さっき出力したdeckとdeck idを
見ればわかるんだけど、ちゃんと
出力されてたらわかりやすいよね。
75000円
GoodGood BadBad
63
???
• デッキの割り当ては試行毎に変わらない
からaddData()したら同じ情報が試行毎に
記録されてもったいないよね。
• 実行中に変化しない値の指定と言えば
Builderの実験情報ダイアログもそうだな。
• 実験情報ダイアログの値はexpInfoで参照
できるんだから、expInfoに追加すればい
いのでは? expInfo['session']
64
trialルーチン
• code_trialの「実験開始時」に以下のコードを追加する。
expInfo['deck_list'] = str(deck_list)
csv形式 xlsx形式
試行毎に出力されてしまう
1回のみ表示される
CSV形式しか使わないなら
結局試行毎に出力されちゃ
うけど、expInfoに関する
テクニックの例題というこ
とで。
65
作業しましょう!
Step9:
音でフィードバックする
77500円
-2500円
5000円
Beep!罰金が科せられたときにビーって
音を鳴らしたいな。
BuilderにはSoundっていうコン
ポーネントがあるから多分出来る
でしょ。
66
• Soundコンポーネントは音声ファイルを
指定したり周波数や波形を指定すること
も出来るのか。まあ今回はファイルを用
意するか。
• 問題はどうやって罰金の時だけ再生する
かだけど…。あぁ、「開始」に「条件
式」っていう選択肢があるな。罰金の時
はpenalty < 0が成り立つからこれを使え
ばいけるかも。
67
feedbackルーチン
• Soundコンポーネントを追加して名前をsound_fbにする。
• sound_fbの「開始」を「条件式」にしてpenalty < 0と入力する。
• sound_fbの音をQuiz-Wrong_Buzzer02-1.mp3にする。
音声素材:Music is VFR 「不正解02」
http://musicisvfr.com/free/se/quiz01.html
音声データはMusic VFRさんのフリー素材を使わせてもらいました。
条件式の評価はルーチン実行中に行われるので、Step6の所持金の時とは
異なりsound_fbがcode_fbの上にあっても期待通り動作します。
さあこれで完成、と思いきや…?
68
作業しましょう!
うげえ、なんだこのエラーは。
よく見るとsndinfo:failed to open file.って書いてあるから音声ファイルが開けな
いのか。
エラーメッセージはTracebackを順番に眺めていくのが基本だと思うけれど、
今回はその上に答えが書いてあったな。気を付けないと。
69
• 音声ファイルを開けない場合、まず音声
ファイル自体が壊れていないか確認する
(通常のプレイヤーで再生できるか?)。
• 音声ファイルを置く場所が間違っていな
いか確認する。
• どちらでもないなら、たぶんオーディオ
ライブラリが音声ファイル形式に対応し
ていない。ライブラリを変更するか、
ファイル形式を変換する。
70
pygame SDL (Simple DirectMedia Layer)をPythonから便利に出来るwrapperで、昔の
PsychoPyはaudioもvisualもpygameをサポートしていた。しかしpygameの
開発はほぼ停止してしまったため、現在はvisualはpyglet、audioは下記の
ライブラリを使用するようになっている。
一応今でも(入れれば)使える。
pyo Cで書かれたオーディオ信号処理ライブラリ。PsychoPyでは音声の再生
だけでなく録音にも使っている。機能的には良いんだけど残念ながら不
安定で実験終了時にコアダンプを吐いたり日本語OSでデバイス情報を
得ようとするとUnicodeエラーで落ちたりする。
pysoundcard オーディオ信号処理ライブラリportaudioのwrapper。録音に対応してい
るけどPsychoPyではサポートしていない(pyoが使われる)。
sounddevice これもオーディオ信号処理ライブラリportaudioのwrapper。録音に対応
しているけどPsychoPyではサポートしていない(pyoが使われる)。現在開
発中のバージョンのPsychoPyのインストーラーではこのライブラリが
Dependencyに含まれている。
psychopy.soundで定義されているオーディオドライバ
71
この資料作成時の開発環境(PsychoPy 1.82.02, pyo 0.6.6)では
mp3が再生できなかったので、aifに変換してみました。
他にもwavなんかでもいけるはずです。
Step9まで進み、アイオワギャンブリング課題の骨組みもだ
いたい出来たのではないかと思います。
実験に使用するにはもっと見栄えをよくしたり、教示や練
習試行を入れたりしたいところですが、みなさんが各自で
挑戦してみてください。
72
作業しましょう!
feedbackルーチン
• sound_fbの音をQuiz-Wrong_Buzzer02-1.aifにする。
練習問題
• フィードバック画面で、マウスクリックではなく一定時間経ったら自動的
に次の試行へ進むようにせよ(Codeコンポーネントは使わない)。
• 報酬と罰金の額の更新をCoderで済ませずにBuilderのプロパティを使うよ
うにせよ(その方が可読性が高い)。
• フィードバック画面で、罰金が科せられた時に選択肢したカードの色を赤
色にせよ。
• カード選択の反応時間を保存するようにせよ。Mouseコンポーネントを
使ってもよいが、出来ればCodeコンポーネントを使うこと。
• 実験情報ダイアログから音フィードバックの有無を指定できるようにせよ。
73
補足:複雑なフローの話
• 「PsychoPy Builderで複雑なフローの実験を作成したい方」と
ワークショップの告知に書いてしまったので…
• ループがfor文、ルーチンがwhile文になることを知っていれば、
あとはアイディア次第。
74
レシピ01:
指定したキーを押すまで終了しないループ
ループはfor文なので回数が不明な
繰り返しは苦手。
非現実的なほど大きい繰り返し回
数を指定して、Routine終了時に
breakすると疑似的に実現できる。
不可能なほど大きな
繰り返し回数
75
ルーチン終了時に終了条件が成立
していればbreakすればよい。
Routine終了時に
コードを挿入
終了条件
この試行のデータを
保存するには
nextEntry()が必要
break
ただ単純にbreakすると、breakした
試行のキー押し等が保存されない。
保存する必要がある場合は
thisExp.nextEntry()
を実行して試行が終了したことを
ExperimentHandlerに通知する。
76
レシピ02
フローの条件分岐(ルーチン編)
現在のPsychoPyはフローの分岐をサポートしていないので工夫が必要。
trialルーチンの後、trial_leftまたはtrial_rightルーチンのどちらかへ分岐
したいとする。とりあえずルーチンを直列に並べておき、不要なルー
チンはbreak即座に中断するという方法をとる。
77
trialルーチンの終了時に
フラグをセットする
trial_left, trial_right
ルーチンでは開始時
ではなくフレーム毎の
ところでフラグに従い
break
78
ルーチンの先頭へ
trial_left, trial_rightルーチンを即座に
中断するためには、Codeコンポーネ
ントをルーチンの先頭に置く必要が
ある点に注意。
他のコンポーネントより後に実行し
たいコードがある場合は、Codeコン
ポーネントを2つ使えばよい。
79
レシピ03
フローの条件分岐(ループ編)
ルーチンではなくフローの実行を分岐させたい場合がある。
このような場合はループの実行回数や条件ファイルをCodeコンポーネント
で操作する。
80
「繰り返し回数」を
変数にする。
必要に応じて「繰り返し条件」
も変数にする。
分岐前のルーチンの終了時等で
繰り返し回数の値を設定する。
81
もっと複雑な複雑なフローを!
82
Builderが作るコードを研究すればもっと複雑なフローを組めると
思いますが、そこまで来たらBuilderを使わなくても直接コードを
書く実力が備わっているかと思います。
ぜひ挑戦してみてください。

More Related Content

What's hot

PsychoPy Builder:モジュールの組み込みと視線計測
PsychoPy Builder:モジュールの組み込みと視線計測PsychoPy Builder:モジュールの組み込みと視線計測
PsychoPy Builder:モジュールの組み込みと視線計測HiroyukiSogo
 
グラフィカルモデル入門
グラフィカルモデル入門グラフィカルモデル入門
グラフィカルモデル入門Kawamoto_Kazuhiko
 
トピックモデルの評価指標 Perplexity とは何なのか?
トピックモデルの評価指標 Perplexity とは何なのか?トピックモデルの評価指標 Perplexity とは何なのか?
トピックモデルの評価指標 Perplexity とは何なのか?hoxo_m
 
はじめよう多変量解析~主成分分析編~
はじめよう多変量解析~主成分分析編~はじめよう多変量解析~主成分分析編~
はじめよう多変量解析~主成分分析編~宏喜 佐野
 
条件付き確率場の推論と学習
条件付き確率場の推論と学習条件付き確率場の推論と学習
条件付き確率場の推論と学習Masaki Saito
 
cvpaper.challenge 研究効率化 Tips
cvpaper.challenge 研究効率化 Tipscvpaper.challenge 研究効率化 Tips
cvpaper.challenge 研究効率化 Tipscvpaper. challenge
 
[DL輪読会]Learning Latent Dynamics for Planning from Pixels
[DL輪読会]Learning Latent Dynamics for Planning from Pixels[DL輪読会]Learning Latent Dynamics for Planning from Pixels
[DL輪読会]Learning Latent Dynamics for Planning from PixelsDeep Learning JP
 
先端技術とメディア表現1 #FTMA15
先端技術とメディア表現1 #FTMA15先端技術とメディア表現1 #FTMA15
先端技術とメディア表現1 #FTMA15Yoichi Ochiai
 
強化学習の基礎的な考え方と問題の分類
強化学習の基礎的な考え方と問題の分類強化学習の基礎的な考え方と問題の分類
強化学習の基礎的な考え方と問題の分類佑 甲野
 
[DL輪読会]Model soups: averaging weights of multiple fine-tuned models improves ...
[DL輪読会]Model soups: averaging weights of multiple fine-tuned models improves ...[DL輪読会]Model soups: averaging weights of multiple fine-tuned models improves ...
[DL輪読会]Model soups: averaging weights of multiple fine-tuned models improves ...Deep Learning JP
 
工学系大学4年生のための論文の読み方
工学系大学4年生のための論文の読み方工学系大学4年生のための論文の読み方
工学系大学4年生のための論文の読み方ychtanaka
 
[DL輪読会]NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis
[DL輪読会]NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis[DL輪読会]NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis
[DL輪読会]NeRF: Representing Scenes as Neural Radiance Fields for View SynthesisDeep Learning JP
 
【DL輪読会】How Much Can CLIP Benefit Vision-and-Language Tasks?
【DL輪読会】How Much Can CLIP Benefit Vision-and-Language Tasks? 【DL輪読会】How Much Can CLIP Benefit Vision-and-Language Tasks?
【DL輪読会】How Much Can CLIP Benefit Vision-and-Language Tasks? Deep Learning JP
 
モデル高速化百選
モデル高速化百選モデル高速化百選
モデル高速化百選Yusuke Uchida
 
CatBoost on GPU のひみつ
CatBoost on GPU のひみつCatBoost on GPU のひみつ
CatBoost on GPU のひみつTakuji Tahara
 
不均衡データのクラス分類
不均衡データのクラス分類不均衡データのクラス分類
不均衡データのクラス分類Shintaro Fukushima
 
画像生成・生成モデル メタサーベイ
画像生成・生成モデル メタサーベイ画像生成・生成モデル メタサーベイ
画像生成・生成モデル メタサーベイcvpaper. challenge
 
生成モデルの Deep Learning
生成モデルの Deep Learning生成モデルの Deep Learning
生成モデルの Deep LearningSeiya Tokui
 
社会心理学者のための時系列分析入門_小森
社会心理学者のための時系列分析入門_小森社会心理学者のための時系列分析入門_小森
社会心理学者のための時系列分析入門_小森Masashi Komori
 
時系列予測にTransformerを使うのは有効か?
時系列予測にTransformerを使うのは有効か?時系列予測にTransformerを使うのは有効か?
時系列予測にTransformerを使うのは有効か?Fumihiko Takahashi
 

What's hot (20)

PsychoPy Builder:モジュールの組み込みと視線計測
PsychoPy Builder:モジュールの組み込みと視線計測PsychoPy Builder:モジュールの組み込みと視線計測
PsychoPy Builder:モジュールの組み込みと視線計測
 
グラフィカルモデル入門
グラフィカルモデル入門グラフィカルモデル入門
グラフィカルモデル入門
 
トピックモデルの評価指標 Perplexity とは何なのか?
トピックモデルの評価指標 Perplexity とは何なのか?トピックモデルの評価指標 Perplexity とは何なのか?
トピックモデルの評価指標 Perplexity とは何なのか?
 
はじめよう多変量解析~主成分分析編~
はじめよう多変量解析~主成分分析編~はじめよう多変量解析~主成分分析編~
はじめよう多変量解析~主成分分析編~
 
条件付き確率場の推論と学習
条件付き確率場の推論と学習条件付き確率場の推論と学習
条件付き確率場の推論と学習
 
cvpaper.challenge 研究効率化 Tips
cvpaper.challenge 研究効率化 Tipscvpaper.challenge 研究効率化 Tips
cvpaper.challenge 研究効率化 Tips
 
[DL輪読会]Learning Latent Dynamics for Planning from Pixels
[DL輪読会]Learning Latent Dynamics for Planning from Pixels[DL輪読会]Learning Latent Dynamics for Planning from Pixels
[DL輪読会]Learning Latent Dynamics for Planning from Pixels
 
先端技術とメディア表現1 #FTMA15
先端技術とメディア表現1 #FTMA15先端技術とメディア表現1 #FTMA15
先端技術とメディア表現1 #FTMA15
 
強化学習の基礎的な考え方と問題の分類
強化学習の基礎的な考え方と問題の分類強化学習の基礎的な考え方と問題の分類
強化学習の基礎的な考え方と問題の分類
 
[DL輪読会]Model soups: averaging weights of multiple fine-tuned models improves ...
[DL輪読会]Model soups: averaging weights of multiple fine-tuned models improves ...[DL輪読会]Model soups: averaging weights of multiple fine-tuned models improves ...
[DL輪読会]Model soups: averaging weights of multiple fine-tuned models improves ...
 
工学系大学4年生のための論文の読み方
工学系大学4年生のための論文の読み方工学系大学4年生のための論文の読み方
工学系大学4年生のための論文の読み方
 
[DL輪読会]NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis
[DL輪読会]NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis[DL輪読会]NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis
[DL輪読会]NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis
 
【DL輪読会】How Much Can CLIP Benefit Vision-and-Language Tasks?
【DL輪読会】How Much Can CLIP Benefit Vision-and-Language Tasks? 【DL輪読会】How Much Can CLIP Benefit Vision-and-Language Tasks?
【DL輪読会】How Much Can CLIP Benefit Vision-and-Language Tasks?
 
モデル高速化百選
モデル高速化百選モデル高速化百選
モデル高速化百選
 
CatBoost on GPU のひみつ
CatBoost on GPU のひみつCatBoost on GPU のひみつ
CatBoost on GPU のひみつ
 
不均衡データのクラス分類
不均衡データのクラス分類不均衡データのクラス分類
不均衡データのクラス分類
 
画像生成・生成モデル メタサーベイ
画像生成・生成モデル メタサーベイ画像生成・生成モデル メタサーベイ
画像生成・生成モデル メタサーベイ
 
生成モデルの Deep Learning
生成モデルの Deep Learning生成モデルの Deep Learning
生成モデルの Deep Learning
 
社会心理学者のための時系列分析入門_小森
社会心理学者のための時系列分析入門_小森社会心理学者のための時系列分析入門_小森
社会心理学者のための時系列分析入門_小森
 
時系列予測にTransformerを使うのは有効か?
時系列予測にTransformerを使うのは有効か?時系列予測にTransformerを使うのは有効か?
時系列予測にTransformerを使うのは有効か?
 

PsychoPy Builder:Code Componentの使い方