こがねいろ

いろいろ備忘録

時系列データの保存 [PsychoPy]

はじめに

PsychoPyで,デフォルトの出力以外に実験結果を保存する方法を考えます。
Builderで基本的な骨組みを作り,一部をCoderで補完する方法をとります。

デフォルトの出力

PsychoPyでは,実験中に取得したデータを実験終了時に書き出すことができます。

例えば,「刺激」コンポーネント(例:Textコンポーネント)で次のように設定しておくと,刺激呈示の開始・終了時刻が最後に出力されます。

f:id:gh_nishiki:20210904171408p:plain
Textコンポーネント

「反応」コンポーネント(例:Keyboardコンポーネント)で次のような設定を行うと,押されたキーを保存することができます。

f:id:gh_nishiki:20210904171210p:plain
keyboardコンポーネント

「反応」コンポーネントのうち,一部のコンポーネント(例:Mouseコンポーネント)では,次のような設定でフレームごとの状態を保存することができます。

f:id:gh_nishiki:20210904172040p:plain
Mouseコンポーネント

概要

しかし,実験によっては,より応用的な処理が必要になることがあります。

例えば,ジョイスティックでスライダー(評定尺度のような横線)を操作して,その評定値をフレームごとに取得したいといった場合です。

その場合,ジョイスティックの状態(例:x軸方向の傾き)を取得するのではなく,スライダーの評定値を保存できれば便利です。

今回はその方法を考えていきます。

空の配列を用意する

Builderで,カスタムコンポーネントからCodeコンポーネントを追加しましょう。

Codeコンポーネントを開き,「フレーム毎」より前に処理されるタブ(「実験初期化中」または「実験開始時」)を選択します。

コード欄に次のように書き込み,空の配列を作成しましょう。

今回は,スライダーの評定値(slider_x)とデータを取得した時刻(slider_t)を入れておくために,2つの配列を作成しています。

slider_x = []
slider_t = []
フレームごとに状態を取得して配列に格納する

続いて,Codeコンポーネントの「フレーム毎」のタブを選択し,次のコードを書き込みます。

フレーム毎にスライダーの状態と,現在の時刻を取得して配列に格納しています。

slider_x.append(YourSliderName.markerPos)
slider_t.append(YourRoutine-ClockName.getTime())


ここで,”YourSliderName”と"YourRoutine-ClockName"という名前が出てきましたが,この箇所には各人が実験で使用している変数の名前が入ります。

評定値を取得したいSliderコンポーネントに,"my_sl01"という名前を付けている場合は,"my_sl01.markerPos"と書くことで"my_sl01"のマーカーの位置を取得することができます。

また,実験のRoutineに"my_R01"という名前を付けている場合は,"my_R01Clock.getTime()"でRoutine開始からの経過時間を取得することができます。

(※ "Clock"と"getTime"の大文字-小文字に注意しましょう。)


詳しくは,下記のサイトを参照してください。
スライダーのマーカー:https://psychopy.org/api/visual/slider.html
ルーチンの経過時間:Pythonで心理実験 - 例題18-5 — 十河研究室


データを書き出す

ここまでの処理で,Pythonの配列の中に①スライダーの評定値と②それに対応する時刻が入れられている状態になりました。

最後にそのデータを書き出します。

データの書き出しは,必ずしもデータを取得したCodeコンポーネント内で行う必要はありません。

データ取得以降であれば,別のRoutineで行っても差し支えありません。

今回は,同一Codeコンポーネント内で書き出しまで行ってしまいましょう。


Codeコンポーネントの「Routine修了時」のタブを選択し,次のコードを書き込みます。

# ライブラリのインポート
import csv

# データの書き込み
my_data = [list(x) for x in list(zip(slider_t, slider_x))]
path = r'data/{}_{}_{}_additional.csv'.format(data.getDateStr(format="%Y%m%d-%H%M"), expInfo['participant'], expName)
with open(path, 'w', newline='') as f:
    w = csv.writer(f)
    w.writerows(my_data)


はじめに,ライブラリ(csv)をインポートしています。

これはcsvファイルの書き出しに使用しています。

(※ インポートはいつでも構わないので,基本的に私は管理しやすいように実験の冒頭で行います。)


続いて,zipを用いて,1次元の配列2個を一つの2次元配列にまとめています。

「何秒目に,どの評定値か」をセットして縦に(列方向に)並べているイメージでしょうか。

この処理を挟むことで,末尾にある"writerows"を使用できます。


"path="の行では,csvファイルをコンピュータ上のどこに作成するかを指定しています。

デフォルト状態のPsychoPyは,実験プログラムが置かれているディレクトリ上にある"data"のフォルダにデータを出力するので,それに合わせて"data/"からパスを書き始めるとよいかもしれません。


なお,デフォルトのPsychoPyは,月の名前を省略した英名で出力します。

そのため,例えば3月と4月に実験を行うと,"Mar"と"Apr"という単語が混在することになります。

しかし,Windowsエクスプローラー上では,多くの場合アルファベット順にファイルが整理されますので,4月のファイル"Apr"の方が3月"Mar"のファイルよりも上にくることになります。

この状態は直感に反するので,実験実行日時の出力を書き換えるために下記の書き方をしています。

data.getDateStr(format="%Y%m%d-%H%M")


また,"expInfo['participant']"ですが,実験開始時に入力する実験情報ダイアログに"participant"という項目を設定しない場合は,表現を適宜変更してください。


おわりに

以上の処理を行うことで,時系列データを書き出すことができました。