平均、標準偏差

「Niblackの手法」という二値化のアルゴリズムをコーディングしていたのですが、その中では平均と標準偏差を求める処理が必要になります。ものすごく端折って書くと、最初はこのような感じで求めていました。

int[] array = new int[]{1, 7, 3, 8, 9, 4};
double sum = 0;

foreach(int i in array){ 
    sum += i;
}
double mean = sum / array.Length;        // 平均

sum = 0;
foreach(int i in array){ 
    sum += Math.Pow(i - mean, 2);
}

double variance = sum / array.Length;   // 分散
double stddev = Math.Sqrt(variance);    // 標準偏差

分散の式
\rho^2 = \frac{1}{n} \sum_{i=1}^{n} \left( x_{i} - \bar{x} \right)^2
を直訳した形ですが、これだとループが2つあるので効率が悪いです。実際、このときは画像処理に8秒程もかかりました。


統計学の本などで分散の式が載っている場合、大抵式が2通りぐらい載っている気がします。そのもう一つの方で以下のように書き換えることで、ループは1つで済みます。

int[] array = new int[]{1, 7, 3, 8, 9, 4};
double sum_m = 0, sum_v = 0;

foreach(int i in array){ 
    sum_m += i;
    sum_v += i*i;
}

double mean = sum_m / array.Length;
double variance = (sum_v / array.Length) - (mean * mean);
double stddev = Math.Sqrt(variance);

こちらの場合、画像処理は2秒程にまで高速化されました。