JavaScriptのArray
クラスにはECMAScript 5.1以降で、配列要素を操作する新しいメソッドが備わっています。その中からArray.reduce()
とArray.map()
の使い方として、配列要素の標準偏差を求めてみましょう。配列要素をfor
文で取り出して計算するより、すっきりと導けます。
#標準偏差とは
「標準偏差」は、データのばらつきを表す指標です。まず平均を計算したうえで、各データと平均値の差を2乗して要素数で割った「分散」を求めます(「【統計学】初めての「標準偏差」(統計学に挫折しないために)」参照)。
分散 = \frac{(データ1 - 平均)^2 + (データ2 - 平均)^2+ … +(データn - 平均)^2}{n}
そうして得た分散の正の平方根が「標準偏差」で、記号${\sigma}$(シグマ)を使って表します。データの分布の基本的なモデルとされる「正規分布」では、平均値±${\sigma}$の値の範囲にデータの7割弱が含まれます(図001)。
標準偏差 = \sqrt{分散}
####図001■正規分布と標準偏差
>> Widipediaより引用
この標準偏差を使ったのが、テストの「偏差値」です。平均を50とし、そこからの差は標準偏差$\sigma$を10として測ります。すると、平均値にかかわらず、データ全体の中の位置づけが得られるのです。偏差値60以上は15%ほど、70を超えるのは2%ちょっとということになります。
#配列要素の平均を求める
では、JavaScriptに戻りましょう。Arrayクラスのメソッドで要素の平均を求めます。用いるのはArray.reduce()
メソッドです。引数に与えた関数で要素を順番に処理し、結果の戻り値はつぎの要素に渡します。
前の要素に今の要素を順に加えていけば、合計が得られます。つぎのように、それを要素数で割れば平均です。引数にはアロー関数式を用いました。
const array = [6, 4, 6, 6, 6, 3, 7, 2, 2, 8];
const average = array.reduce((previous, current) =>
previous + current // 前の要素につぎの要素を足す
) / array.length; // 要素数で割る
console.log(average); // 5
#各要素について平均値との差の2乗を求める
平均が得られたら、もとの配列のそれぞれの要素について、平均値との差の2乗を求めます。このとき使うのは、Array.map()
メソッドです。Array.reduce()
と同じく、渡した関数で配列要素を順に処理します。違うのは、戻り値を要素とする新たな配列が返されることです。
するとつぎの式で、平均値との差の2乗を要素とする配列が得られます。なお、べき乗演算子**はECMAScript 2016で採り入れられました。
const squaredDifference = array.map((current) => {
const difference = current - average; // 平均値との差を求める
return difference ** 2; // 差を2乘する
});
console.log(squaredDifference); // [1, 1, 1, 1, 1, 4, 4, 9, 9, 9]
#配列要素の分散を求める
要素の平均値との差の2乗を足し合わせて、平均すれば分散です。つぎのように、前に平均を求めたときと同じ式になります。
const variance = squaredDifference.reduce((previous, current) =>
previous + current // 前の要素につぎの要素を足す
) / array.length; // 要素数で割る
console.log(variance); // 4
分散と聞くと想い起こすのは、ある科学者が述べたといわれる宝くじを買う理由です。曰く「期待値でなく分散を買うのだ」と。宝くじは割りが最悪なギャンブルで、期待値は半額以下です(「統計と確率の見方・考え方」参照)。けれど、分散は振れ幅が大きいので、一攫千金の夢があるというわけです。ものは言いようといえます。
#分散の平方根が標準偏差
分散が導ければ、あとはその正の平方根を求めるだけです。Array.map()
メソッドは配列を返しますので、ドット(.
)をつなげればさらにメソッドが呼び出せます。
コードをつぎにまとめましょう。引数に関数を使った記述は少し長いものの、for
ループで求めるより、計算の手順がわかりやすいのではないでしょうか。
const array = [6, 4, 6, 6, 6, 3, 7, 2, 2, 8];
const average = array.reduce((previous, current) =>
previous + current // 要素をすべて足す
) / array.length; // 平均を求める
const standardDeviation = Math.sqrt( // 分散の平方根を求める
array.map((current) => { // 各要素について
let difference = current - average; // 平均値との差を求める
return difference ** 2; // 差を2乘する
})
.reduce((previous, current) =>
previous + current // 差の2乗をすべて足す
) / array.length // 差の2乗の平均が分散
);
console.log(standardDeviation); // 標準偏差: 2.0