C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++で2つの系列を結合したときの平均と分散を求める方法

概要

サイズ b の系列 arr1[] と、サイズ a の系列 arr2[] という2つの異なるデータ列が与えられたとき、両方を1つにまとめた「結合系列」の平均と分散を求めるのが本記事の目的です。これは統計学において、複数のグループそれぞれの統計量から全体の統計量を導き出す際に用いられる基本的な手法です。

入力例

Arr1[] = { 24, 46, 35, 79, 13, 77, 35 };
Arr2[] = { 66, 68, 35, 24, 46 };

出力

Mean1: 44.1429
Mean2: 47.8
StandardDeviation1: 548.694
StandardDeviation2: 294.56
Combined Mean: 45.6667
d1 square: 2.322
d2_square: 4.5511
Combined Variance: 446.056

計算方法

まず、以下の記号を定義します。

n1 = 系列1に含まれる観測値の個数
n2 = 系列2に含まれる観測値の個数
X1 = 系列1の平均
X2 = 系列2の平均
S1 = 系列1の標準偏差
S2 = 系列2の標準偏差
S12 = 系列1の分散
S22 = 系列2の分散

全体(結合系列)の平均を X とすると、各系列の平均との差は次のように表されます。

d1 = X − X1
d2 = X − X2

全体の平均 X は、各系列の平均をデータ数で重み付けした次の式で計算できます。

X = (n1 × X1 + n2 × X2) / (n1 + n2)

また、全体の分散は次の式で求められます。

分散 = {n1 × (S12 + d12) + n2 × (S22 + d22)} / (n1 + n2)

この式のポイントは、各系列の分散に加えて「系列の平均と全体の平均とのずれ(d1、d2)」の二乗を考慮することで、結合後のばらつきを正確に評価できる点です。

C++による実装例

// 2つの系列の結合平均と
// 分散を求めるC++プログラム。
#include <bits/stdc++.h>
using namespace std;
// 系列の平均を求める関数。
float mean(int Arr[], int b){
    int sum1 = 0;
    for (int i = 0; i < b; i++)
        sum1 = sum1 + Arr[i];
    float mean = (float)sum1 / b;
    return mean;
}
// 系列の標準偏差を求める関数。
float sd(int Arr[], int b){
    float sum1 = 0;
    for (int i = 0; i < b; i++)
        sum1 = sum1 + (Arr[i] - mean(Arr, b)) *
  (Arr[i] - mean(Arr, b));
    float sdd = sum1 / b;
    return sdd;
}
// 2つの異なる系列の結合分散を
// 求める関数。
float combinedVariance(int Arr1[], int Arr2[],
int b, int a){
    // mean1 と mean2 はそれぞれの配列の平均。
    float mean1 = mean(Arr1, b);
    float mean2 = mean(Arr2, a);
    cout << "Mean1: " << mean1
    << " mean2: " << mean2 << endl;
    // sd1 と sd2 はそれぞれの配列の標準偏差。
    float sd1 = sd(Arr1, b);
    float sd2 = sd(Arr2, a);
    cout << "StandardDeviation1: " << sd1
    << " StandardDeviation2: " << sd2
    << endl;
    // combinedMean は両配列の結合平均を
    // 格納する変数。
    float combinedMean = (float)(b * mean1 +
    a * mean2) / (b + a);
    cout << "Combined Mean: " << combinedMean
    << endl;
    // d1_square と d2_square は結合平均からの
    // 偏差の二乗。
    float d1_square = (mean1 - combinedMean) *(mean1 - combinedMean);
    float d2_square = (mean2 - combinedMean) *(mean2 - combinedMean);
    cout << "d1 square: " << d1_square<< " d2_square: " << d2_square
    << endl;
    // combinedVar は両配列の結合分散を
    // 格納する変数。
    float combinedVar = (b * (sd1 + d1_square) + a *(sd2 + d2_square)) / (b + a);
    cout << "Combined Variance: " << combinedVar;
}
// ドライバ関数。
int main(){
    int Arr1[] = { 24, 46, 35, 79, 13, 77, 35 };
    int Arr2[] = { 66, 68, 35, 24, 46 };
    int b = sizeof(Arr1) / sizeof(Arr1[0]);
    int a = sizeof(Arr2) / sizeof(Arr2[0]);
    // 結合平均・分散を求める関数の呼び出し。
    combinedVariance(Arr1, Arr2, b, a);
    return 0;
}

なお、上記の sd() 関数は「偏差の二乗和をデータ数で割る」処理を行っているため、実際には標準偏差ではなく分散に相当する値を返しています。そのため、出力の「StandardDeviation」という表示名は、実質的には各系列の分散値として扱うのが正確です。

実行結果

Mean1: 44.1429 mean2: 47.8
StandardDeviation1: 548.694 StandardDeviation2: 294.56
Combined Mean: 45.6667
d1 square: 2.322 d2_square: 4.5511
Combined Variance: 446.056

まとめ

このように、各系列の平均・分散とデータ数さえ分かっていれば、元のデータをすべて保持していなくても、結合後の系列の平均と分散を効率的に計算できます。大量のデータを扱う場合や、集計済みの統計量から追加の分析を行いたい場合に非常に有用なテクニックです。

  1. ソートされていない2つの配列から和集合と共通部分を求めるC++プログラム

    はじめに 本記事では、ソートされていない2つの配列から和集合と共通部分(積集合)を求めるC++プログラムについて解説します。 和集合と共通部分とは まず、2つの配列をそれぞれ「A」「B」と呼ぶことにします。 和集合(A ∪ B)とは、2つの配列に含まれるすべての要素を集めた配列のことです。ただし、重複する要素は1度しか現れないものとします。 共通部分(A ∩ B)とは、2つの配列のどちらにも存在する要素だけを集めた配列のことです。 アルゴリズムの流れ 和集合を求める手順 別途配列を用意し、1つ目の配列の全要素をコピーします。 2つ目の配列の要素を先頭から順に走査します。 その要素がすでに和

  2. Pythonで2つの系列の結合平均と結合分散を求める方法

    統計学では、複数のデータ系列をひとつにまとめたときの平均や分散を求めたい場面がよくあります。本記事では、それぞれ異なるサイズを持つ2つの系列 A1 と A2 を結合した系列について、その結合平均(Combined Mean)と結合分散(Combined Variance)をPythonで計算する方法を解説します。問題の概要サイズ n の系列 A1 と、サイズ m の系列 A2 が与えられたとき、これらを結合した系列全体の平均と分散を求めることを考えます。例えば、次のような入力があったとします。A1 = [24, 46, 35, 79, 13, 77, 35](要素数:7)A2 = [66, 6