JavaScript+Hyperappで心理学実験プログラムを作った

これです(github)。

僕の学科では学生が実験に参加しつつその実験についてレポートを書くという授業が多く行われている。そこで行う実験は古典的なものが多いのだが、大昔に書かれた実験プログラムがメンテナンスされずに使われ続けているということがある。

今回書いた記憶実験のプログラムもそうで、誰がいつどうやって作ったかわからないexeファイルが受け継がれ使われ続けてきた。しかし内部の処理がわからないので細かい仕様がわからず、いろいろ試してみて推測することしかできない状態だった。さらにいつ動かなくなるかもわからない。

そこでこのプログラムを移植(ソースコードがないので移植と言うかは微妙だが)しようという話になった。当初はPythonが候補に上がっていたが、多数の学生に授業中に同時に行わせるにあたり、Pythonをexeに固めたものは容量が大きくなりすぎダウンロードが長引く懸念があった(経験的には数十MB)。そこでJavaScriptでの制作を提案した。サンプルを作って披露したところゴーサインが出たので制作した。

動作は単純で

  1. x桁のランダム数列を3秒間表示
  2. 数列を消し5秒間待つ
  3. 参加者が数列を思い出して回答する
  4. 正誤を3秒間表示
  5. 桁数を変更し、1に戻る

というものだ。5の桁数変更のアルゴリズムには上下法や恒常法などがある。

上下法は正解すれば次は1段階難しく、不正解なら次は1段階簡単にするというアルゴリズムだ。これによって参加者の正解できる限界の桁数に収束する。メリットは試行数が少なく済むこと。

恒常法は一定の範囲の桁数をランダムな順番で課し、桁数を横軸に、正解率を縦軸にプロットすることで正解率を桁数を結びつける関数を得る。そして正解率50%(任意の値)に相当する桁数をその人の限界とする。メリットは関数そのものが得られるため多様な分析が可能であること。

心理学の実験は基本的にはwebではやらない。それは参加者の環境が統一できないからだ。MATLAB+Psychtoolboxが主流で、Python+Psychopy(pygame)もある。しかしポータビリティは低い。GUIを使うプログラムはDockerで動かすのは不便で、できてもパフォーマンスに不安がある。

そこまで環境にこだわらない実験や、今回のように同じ部屋で多くのPCで実験を行うときにはポータビリティの高いwebプログラミングによる実験は便利だ。そもそもGUIを扱うノウハウやライブラリという点ではJavaScript、というよりブラウザという環境が優れている。

Life is Tech

とかいうTシャツを来た中高生くらいの集団が夕食時に食堂にたくさんいた。なんの集団だろうと調べてみたら中高生にプログラミングを教えるスクールらしい。

そういえば、ドワンゴのインターンが始まったのもちょうど1年ほど前だ。自己流のいい加減なコードとそれっぽい文章を提出したら全国の激ヤバ猛者が集まるインターンになぜか参加を許可され、何を学んだか列挙できないほど豊かな体験をした。結局それが布石となって就職も決まった。

別にプログラミングじゃなくていいが、まとまった時間を何かに注ぎこむこと、同世代の強者を知ること、プロの技を教わること、そういう活動が自分の世界を広げる。

最近は研究しかしてないので書くことがない。学会の参加登録が済んだので今日は本の返却等細々した作業を片付けつつ、これから何しようかなあと考えていた。もちろん実験を進めねばならないのだが、そのまえに分析法や実験手続きを確立しておきたい。なるべく自動化。ただでさえ参加者のリクルートや謝礼手続きで手間がかかるので、実験と分析くらいは自動化したいものだ。

PypeRなるライブラリを使うとPythonからRを呼び出せる。複雑な統計分析はRを使う必要があるが、PypeRがあればPandasとも連携できるので捗りそうだ。

うーん、書けそうで書けない。疲れているんだろうか。それとも人生のネタが切れたんだろうか。酒が足りないのか?

実験プログラム

いい加減研究しないとまずい(してないわけではない)ので最近は実験プログラムをゴリゴリ書いている。pygameをベースに、特殊な刺激を呈示するときはpsychopyを使ったり、マイクを拾うためにpyaudioを使ったりしている。コンピュータは便利だ。たくさんの実験参加者に全く同じ刺激を呈示することも、参加者の行動をミリ秒単位で記録することもコンピュータなしでは不可能だっただろう。

よく考えると、人間に何かを見せてそれに応じて何かを入力させるのはゲームと同じだ。だからゲームプログラミングのライブラリを使うのは理にかなっている。Pythonは遅いので一般論としてゲームプログラミングには向かないが、僕の研究では3DCGのレンダリングをするわけではないし、タイミングを記録することを考えても100fps出れば十分なのでPythonで事足りる。

マイクやらスピーカーやら圧力センサやらのデバイスを使うとなると低レイヤーで問題が発生することが多い。windows上でその手の問題を地道に解決していくのは正直かなりしんどい。

うん。しんどい。

ドワンゴエンジニアハッカソンに参加した

※この記事は他人の金で『Asahi スーパードライ』を飲んで帰宅したあとに書かれた。

ハッカソンは初めて。殺伐としているのかなと思いきや交流しつつ作業を進められて大変楽しかった。発表者も皆独自の視点でお題を(無理やり)解釈して面白いものを作っていて、盛り上がった。バーチャルマシンの起動を400人で見守って成功したら会場がどっと湧くなどという体験は滅多にできるものではない。

私はといえば、お題が「バーチャル」だったので以下のように考えた。

作ったものはここ。Flaskでサーバー立ててWebサービス化しようかとも思ったけど時間足りなかった。いちいちcsvから読んでるのもダサいのでDB使いたかったけど時間(略)。

自分で使ってみて面白いのは毎回違う文章が生成される点で、パワーワードが生成されるまで連打してしまう。面白すぎてクスクス笑ってたら隣の人に怪しまれた。ためしに自分の過去の文章を放り込んでみた。

大成功であった。マヨネーズが焼きそばと相性が良いのは既知のことであったが、さらに酸味と塩味が融合したマヨネーズが鶏胸肉の酸味を覆い隠しつつ焼きそばの味になじませている。完全勝利である。

この成功は誰にも分らない。たといマヨネーズの焼きそばは相性ののに既知しもことに酸味を覆いの塩味なし。そういう完全、勝利は、向うの山の頂の巖に上り、空谷に向って吼える。

 

睡眠は偉大だ。1日1度の食事さえとれればあとは無限に寝ていたい。さらに睡眠には眠気がとれるという副産物まである。また、睡眠は認知症のリスクを減らす数少ないエビデンスのある予防法でもある。

およそ睡眠の働き、偉大を進めて進まざるものあることなし。1なら、勿論、日の1へとれれ度き食事である。睡眠眠気副産物行は、息をとれるで、叢中の声のある不思議に聞入っていた。「善くぞ減らす来睡眠ある。

うん。格調高い。次は有名な名文から

吉野家ってのはな、もっと殺伐としてるべきなんだよ。
Uの字テーブルの向かいに座った奴といつ喧嘩が始まってもおかしくない、
刺すか刺されるか、そんな雰囲気がいいんじゃねーか。女子供は、すっこんでろ。

その吉野家、のの殺伐も少からず、このんの下人のSentimentalismeに影響した。
座っと、字のテーブルには、向かいにいた奴、喧嘩かの死骸が、無造作に始まってあるが、火の光の及ぶ範囲が、思ったより狭いので、数は幾つともわからない。
雰囲気のんにごろりと刺す刺さた。子供とろとの交際は、この時までは余所目にすっこんより清白なりき。

夏の怪異―Python3のクラス変数のスコープ

さて、今日Pythonを書いていたら、妙なエラーに遭遇した。同じ役割を持つ変数をまとめておくためにクラス定義を用いて以下のようなコードを書いた(このようなクラスの使い方は悪くはない)。

これを見ただけで「あっ…」となる人はすごい。なんとこのコードは以下のようなエラーを吐く。

原因究明に時間を要したが、説明しているブログがあった。

【python】クラス変数のスコープには注意が必要

python – Accessing class variables from a list comprehension in the class definition – Stack Overflow

要約すると、クラス変数の中にスコープがネストされた場合、クラス変数の定義されたスコープは読まないよ、ということを言っています。リスト内包表記はスコープを作るので、この問題が起こります。

PEP 227 — Statically Nested Scopes | Python.org

「それができるとメソッド定義で事故るだろーが、親切なpython様が対策してやってるんだよ」と書いてあります。

なるほど…。全然知らなかった。Pythonでは内側のスコープから外側のスコープを読めないということは原則的にはないので驚いた。

なお、本日書いたなかでぶっちぎりのクソコードはこれ。PythonとRubyはよくライバルみたいな扱いされるけど、こういうのを書いているとRuby使いたいと思う。でもPythonの方がライブラリが充実してるんだよなあ。