APL/J言語で標準偏差


以前TOEICを受験したことがありまして、なんと975点という高得点でした。で975点がどんな点かというと、受験した第138回の発表によると、平均586.1点、標準偏差が171.8点とある。平均と標準偏差を与えられると、偏差値が計算できて、「計算式: 偏差値 = (10 x (得点 - 平均点))/標準偏差 + 50」によって、偏差値72.6が算出されます。ここまでは自慢話です。

さて、APL/J言語で配列の個数とか平均とか、標準偏差を計算する話です。勉強しながらなので、行ったり来たりしますが、そこはご容赦下さい。
まず、適当な得点の配列を考えます。

   a =: 200 300 400 500 600 700 438 580 550 800

なんとなくTOEICの点数ふうですね。これだと平均が600百点あたりかな、偏差は150点あたりかな、とメドをつけます。

   #a
10

#(シャープ)は単項動詞(引数を右側だけとる場合)としては配列の個数を返します。今回はaの要素の個数は10個ということ。

   +/a
5068

/(スラッシュ)はその直前の動詞を右側の配列の要素すべての間に置くという意味の副詞で、今回の場合だと200+300+400+500+600+700+438+580+550+800の意味になります。
次に平均を求めます。

   (+/%#) a
506.8

%(パーセント)はJ言語での割り算で、今回カッコの中の意味は合計を個数で割る、という意味になります。動詞が3つ並んだ形をカッコでくくってある場合、引数は左右の動詞にかかかって、最後に真ん中の動詞が左右の結果に作用します。
つまり、=> (+/a) % (#a) => 5068 % 10 => 506.8となります。
さてそれぞれの要素から平均を引いたものの自乗の合計の平方根を個数で割ったのが標準偏差です。だんだんややこしくなってきました。あとで整理するとして、とりあえず答え(らしきもの)出そう。

   (%: +/ *:(-+/%#) a) % #a
54.0631

むむう、違っているような気がするなぁ。ここらへんでテキストを見よう。

 ┌─────────────────┬─────────────────┐
 │m28=: %:@m27"1                    │Standard deviation of y           │
 ├─────────────────┼─────────────────┤
 │m27=: (+/@(*:@(] - +/ % #)) % #)"1│Sample variance (dispersion) of y │
 └─────────────────┴─────────────────┘

これは、JについてくるJ Phrasesというよく使われるスクリプト集みたいなものにあったものです。Standard deviationというのが分散でSample variance (dispertion)というのが標準偏差に相当すると思う。やってみよう!

   m27=: (+/@(*:@(] - +/ % #)) % #)"1
   m27 a
29228.2
   m28=: %:@m27"1
   m28 a
170.962

さっきの値より、ずっと正しそうな値になりました。途中の数字を見てわかるのはわたしは最後に個数で割ればいいとおもっていたけれど、平方根を求める前に個数で割らなければいけないようです。
各プログラムの最後に"1(クオートいち)がついているけどこれは必要なのかなぁ、やってみよう。=>結果、とってみても同じ結果になりました。ただ点数を2次元にしてテーブルにすると、"1がついた場合は横の分散とか偏差、"1を取ると縦の分散とか標準になりました。これはこれなりにおもしろいと思います。
あと、今までに出てきてない記号として](みぎブラケット)があります。これは右側の引数を持ってくる、という意味で、これを使わなくてもプログラムは工夫すれば作れるのですが、使った方がわかりやすくなります。あと@(アトマーク)はその左右の動詞群がひとまとめではないですよ!という記号で、右をやってから次の左の動詞を使うという意味になります。ここでは使っていませんが、a:(アトマークコロン)というのもあって、それだと右の結果が配列の場合、配列の要素一つ一つに左の動詞を使うのではなく、全体に使うという意味になります。今回のm27で左の方の+/@((プラススラッシュアトマーク左カッコ)というのがほんとはそれにあたるので、私だったら@:(アトマークコロン)を使って括弧を一セット省略した方がカッコの深さが浅くなって読みやすいと思う。