AIZU ONLINE JUDGE

AOJ ITP1 10_C(Standard Deviation)を解く

AOJ_ITP1_10_C

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 の問題を紹介していきます。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA