見出し画像

高校数学をプログラミングで解く(数学I編)「3-3 分散と標準偏差」

はじめに

今回は、数学Iで学ぶ「分散と標準偏差」について、データの分散と標準偏差を求めるプログラムを作成します。

分散、標準偏差

まず、分散と標準偏差について解説しておきます。

偏差

データの各値$${x}$$と平均値$${\bar{x}}$$との差$${x-\bar{x}}$$

分散

偏差の2乗の平均値

$$
s^2 = \frac{1}{n} \{ (x_1-\bar{x})^2+(x_2-\bar{x})^2+ \cdots +(x_n-\bar{x})^2 \}
$$

なお、分散は

$$
s^2 = \overline{x^2} - \bar{x}^2
$$

と書くことができます。ここで、$${\overline{x^2}}$$は$${x^2}$$のデータの平均値を表します。

$$
\overline{x^2} = \frac{1}{n} (x_1^2+x_2^2+ \cdots + x_n^2)
$$

標準偏差

分散の正の平方根

$$
s = \sqrt{\frac{1}{n} \{ (x_1-\bar{x})^2+(x_2-\bar{x})^2+ \cdots +(x_n-\bar{x})^2 \}}
$$

今回は、データに対してこれらの値を求めるプログラムを作成していきます。

利用するデータの準備

以下で作成する各種プログラムで利用するデータは以下の20個の数を利用します。これは、記事『高校数学をプログラミングで解く(数学I編)「3-1 データの整理、データの代表値」』で利用したものと同じものです。

$$
3 \ 4 \ 9 \ 7 \ 6 \ 10 \ 5 \ 5 \ 7 \ 9 \ 6 \ 8 \ 1 \ 5 \ 7 \ 10 \ 8 \ 6 \ 3 \ 7
$$

なお、プログラムではfloat型の配列として扱います。

  // データ
  int data_num = 20; // データ数
  float[] data = {3,4,9,7,6,10,5,5,7,9,6,8,1,5,7,10,8,6,3,7}; // データ

分散を求める

まず、分散を求めるプログラムを作成します。アルゴリズムは分散の定義通りに行いますが、データの偏差の2乗の平均値を計算する方法とデータの2乗の平均値からデータの平均値の2乗との差を計算する方法の2つがあります。今回は、両方の関数を準備して同じ結果が得られるか確認してみます。

分散を求める関数(データの偏差の2乗の平均値を利用)

データの偏差の2乗の平均値を利用して分散を計算する関数は以下のようになります。なお、偏差や分散を計算する際に、データの平均値を求める必要がありますが、平均値を求める関数は記事『高校数学をプログラミングで解く(数学I編)「3-1 データの整理、データの代表値」』で作成しましたので、そのときのcalcmeanvalue関数を利用します。

// 分散を計算する関数(偏差の2乗の平均値を利用)
float calcvariance(
  int data_num, // データ数
  float[] data // データの配列
){
  // 平均値を計算する
  float mean = calcmeanvalue(data_num, data);
  
  float sum = 0.0; 
  for(int i=0; i<data_num; i++){
    sum += (data[i] - mean) * (data[i] - mean);
  }
  return sum / data_num;
}

ソースコード1 データの分散を求める関数(データの偏差の2乗の平均値を利用)

分散を求める関数(データの2乗の平均値とデータの平均値の2乗との差を利用)

データの2乗の平均値とデータの平均値の2乗との差を利用して分散を計算する関数は以下のようになります。関数名は、データの偏差の2乗の平均値を利用する場合と区別するために、「calcvariance2」としています。

// 分散を計算する関数(データの2乗の平均値とデータの平均値の2乗の差を利用)
float calcvariance2(
  int data_num, // データ数
  float[] data // データの配列
){
  // 平均値を計算する
  float mean = calcmeanvalue(data_num, data);
  
  // x^2の平均値を計算する
  float mean2 = 0.0; 
  for(int i=0; i<data_num; i++){
    mean2 += data[i] * data[i];
  }
  mean2 /= data_num;
  
  // 分散を計算する
  float variance = mean2 - mean * mean;
  
  return variance;
}

ソースコード2 データの分散を求める関数(データの2乗の平均値とデータの平均値の2乗の差を利用)

なお、上記2つの分散を求める関数は、引数にデータ数「data_num(int型)」とデータ「data(float型の配列)」を渡すと、分散を計算して返す関数となっています。

分散を求めるプログラム

それでは、上記2つの分散を求める関数を利用して、データの分散を求めるプログラムを作成します。

// データの分散を計算する
void setup(){

  // データ
  int data_num = 20; // データ数
  float[] data = {3,4,9,7,6,10,5,5,7,9,6,8,1,5,7,10,8,6,3,7}; // データ

  // 分散
  float variance = calcvariance(data_num, data);
  println("データの偏差の2乗の平均値:", variance);
  
  // 分散2
  float variance2 = calcvariance2(data_num, data);
  println("データの2乗の平均値とデータの平均値の2乗の差:", variance2);
  
  
}

// 平均値を計算する関数
float calcmeanvalue(
  int data_num, // データ数
  float[] data // データの配列
){
  float sum = 0.0; 
  for(int i=0; i<data_num; i++){
    sum += data[i];
  }
  return sum / data_num;
}

// 分散を計算する関数(偏差の2乗の平均値を利用)
float calcvariance(
  int data_num, // データ数
  float[] data // データの配列
){
  // 平均値を計算する
  float mean = calcmeanvalue(data_num, data);
  
  float sum = 0.0; 
  for(int i=0; i<data_num; i++){
    sum += (data[i] - mean) * (data[i] - mean);
  }
  return sum / data_num;
}

// 分散を計算する関数(データの2乗の平均値とデータの平均値の2乗の差を利用)
float calcvariance2(
  int data_num, // データ数
  float[] data // データの配列
){
  // 平均値を計算する
  float mean = calcmeanvalue(data_num, data);
  
  // x^2の平均値を計算する
  float mean2 = 0.0; 
  for(int i=0; i<data_num; i++){
    mean2 += data[i] * data[i];
  }
  mean2 /= data_num;
  
  // 分散を計算する
  float variance = mean2 - mean * mean;
  
  return variance;
}

ソースコード3 データの分散を求めるプログラム

このソースコード3を、Processingの開発環境ウィンドウを開いて(スケッチ名を「calcVariance」としています)、テキストエディタ部分に書いて実行すると、図1のように2種類の方法で求めた分散の値が

データの偏差の2乗の平均値で計算: 5.5099993
データの2乗の平均値とデータの平均値の2乗の差: 5.5099983

と、コンソールに出力されます。これらの値は丸め誤差の範囲で一致していることがわかります。

図1 スケッチ「calcVariance」の実行結果

標準偏差を求める

最後に、標準偏差を求めるプログラムを作成します。アルゴリズムは標準偏差の定義通りに行います。標準偏差を求める際に、分散を求める必要がありますが、今回は上記のcalcvariance関数を用いることにしました。

標準偏差を求めるプログラム

標準偏差を求めるプログラムは以下のようになります。

// データの標準偏差を計算する
void setup(){

  // データ
  int data_num = 20; // データ数
  float[] data = {3,4,9,7,6,10,5,5,7,9,6,8,1,5,7,10,8,6,3,7}; // データ

  // 標準偏差
  float sd = calcstandarddeviation(data_num, data);
  println(sd);
    
}

// 平均値を計算する関数
float calcmeanvalue(
  int data_num, // データ数
  float[] data // データの配列
){
  float sum = 0.0; 
  for(int i=0; i<data_num; i++){
    sum += data[i];
  }
  return sum / data_num;
}

// 分散を計算する関数(偏差の2乗の平均値を利用)
float calcvariance(
  int data_num, // データ数
  float[] data // データの配列
){
  // 平均値を計算する
  float mean = calcmeanvalue(data_num, data);
  
  float sum = 0.0; 
  for(int i=0; i<data_num; i++){
    sum += (data[i] - mean) * (data[i] - mean);
  }
  return sum / data_num;
}

// 標準偏差を計算する関数
float calcstandarddeviation(
  int data_num, // データ数
  float[] data // データの配列
){
  // 分散を計算する
  float variance = calcvariance(data_num, data);
  
  // 標準偏差を計算する
  float sd = sqrt(variance);
  
  return sd;
}

ソースコード4 標準偏差を求めるプログラム

なお、標準偏差を求める部分は関数化しており、引数にデータ数「data_num(int型)」とデータ「data(float型の配列)」を渡すと、データの標準偏差を返す関数となっています。

このソースコード4を、Processingの開発環境ウィンドウを開いて(スケッチ名を「calcStandardDeviation」としています)、テキストエディタ部分に書いて実行すると、図2のようにデータの標準偏差「2.3473387」がコンソールに出力されていることがわかります。

図2 スケッチ「calcStandardDeviation」の実行結果

まとめ

今回は、数学Iで学ぶ「分散と標準偏差」について、データの分散と標準偏差を求めるプログラムを作成しました。
データの分散や標準偏差はデータ解析において平均値、中央値、最頻値と並んで基本的で重要なものとなっていますので、ぜひそれらの計算方法とともに覚えてください。

今回、分散の計算では、2種類の計算方法があり、その両方で分散を求めてそれらを比較しました。プログラミングではそのプログラムが正しく実装されているかどうかをテストする必要がありますが、今回のように2種類以上の方法でプログラムを実装して比較することはそのプログラムが正しいことを確認するための1つの方法となります。なんとなく心にとどめておくと、今後役に立つかもしれません。

参考文献

改訂版 教科書傍用 スタンダード 数学I(数研出版、ISBN9784410209178)

この記事が気に入ったらサポートをしてみませんか?