Aizu Online Judge(AOJ)が提供している「プログラミング入門」(ITP1)の10_C問題をC++とPython で解いてみました。
ITP1 のトピック10では、数学関数について学びます。「基礎的な数学関数を学習します。」とあります。この学習コースを通じて、Python に慣れていきたいと考えています。
問題(10_C: Standard Deviation)
問題はリンク先をご覧ください。
AOJ ITP1 10_C問題:Standard Deviation
平均、分散、標準偏差を計算する問題です。
平均、分散、標準偏差
この問題で計算する平均、分散、標準偏差は、高校で履修する数学Ⅰで学びます。
平均の定義
$n$ 個のデータを $x_1, x_2, \dots, x_n$ とするとき、平均 $m$ は、以下の式で計算できます。平均値は、データの代表値として、よく使われています。
$$m = \frac{1}{n}(x_1 + x_2 + \cdots + x_n)$$
分散と標準偏差の定義
$n$ 個のデータの平均を $m$ とするとき、分散は $s^2$ は、以下の式で計算できます。分散は、データのバラつきを表す指標と考えることができます。
$$s^2 = \frac{1}{n} \sum^n_{i = 1} (x_i – m)^2 = \frac{1}{n} \left((x_1 – m)^2 + (x_2 – m)^2 + \cdots + (x_n – m)^2 \right)$$
分散 $s^2$ は、単位も2乗になっています。分散の正の平方根 $s$ を標準偏差と呼びます。標準偏差は、データと単位が一致します。
$$s = \sqrt{\frac{1}{n} \sum^n_{i = 1} (x_i – m)^2} = \sqrt{\frac{1}{n} \left((x_1 – m)^2 + (x_2 – m)^2 + \cdots + (x_n – m)^2 \right)}$$
データの2乗の平均を $\bar{x^2}$ とします。この場合、分散は以下の式でも計算できます。
$$s^2 = \bar{x^2} – m^2$$
分散は、2乗の平均から平均の2乗を引いた値となります。定義に従い計算していけば、証明できます。
解答案
C++ プログラム例(ITP1 10_C)
平均を求めてから、分散を求めました。データを x、平均を m、分散を s2 としました。
#include <iostream>
#include <ios> // fixed
#include <iomanip> // setprecision
#include <vector>
#include <cmath>
using namespace std;
int main()
{
while (1) {
int n;
cin >> n;
if (n == 0) {
break;
}
vector<double> x(n);
double m = 0.0;
for (int i = 0; i < n; ++i) {
cin >> x[i];
m += x[i];
}
m /= (double)n;
double s2 = 0.0;
for (int i = 0; i < n; ++i) {
s2 += (x[i] - m) * (x[i] - m);
}
s2 /= (double)n;
cout << fixed << setprecision(5) << sqrt(s2) << endl;
}
return 0;
}
次に、データの2乗の平均から平均の2乗を引いて分散を求めます。この場合、データを記憶する配列(vector)を用意する必要はなく、データの走査も1回で計算ができます。
プログラムは、以下となります。
#include <iostream>
#include <ios> // fixed
#include <iomanip> // setprecision
#include <vector>
#include <cmath>
using namespace std;
int main()
{
while (1) {
int n;
cin >> n;
if (n == 0) {
break;
}
double m = 0.0;
double m2 = 0.0;
for (int i = 0; i < n; ++i) {
double x;
cin >> x;
m += x;
m2 += x * x;
}
m /= (double)n;
m2 /= (double)n;
cout << fixed << setprecision(5) << sqrt(m2 - m * m) << endl;
}
return 0;
}
Python プログラム例(ITP1 10_C)
Python 版では、まず定義に従いプログラムします。
import math
while True:
n = int(input())
if n == 0:
break
x = list(map(float, input().split()))
m = sum(x) / float(n)
s2 = sum([(t - m) ** 2 for t in x]) / float(n)
print(f"{math.sqrt(s2):.5f}")
数理統計関数を処理する statistics モジュールが提供している pstdev を使う方が、Python らしいかもしれません。
import statistics
while True:
n = int(input())
if n == 0:
break
x = list(map(float, input().split()))
print(f"{statistics.pstdev(x):.5f}")
上記プログラムは、すべて AOJ で「AC(Accepted=正解)」と判定されます。
最後に
前回に続き、高校で履修する数学Ⅰで取り扱う内容について計算しました。Python は、標準モジュールが充実していることが確認できました。
引き続き、ITP1 の問題を紹介していきます。