【MQL5】Cov関数について

MQL5リファレンス
スポンサーリンク
スポンサーリンク

Cov関数の働き・役割

Cov関数は、指定したデータセットに基づいて共分散行列を計算するために使用されます。共分散行列は、複数の変数間の関係性を数値で表したものです。

この関数は、データがどの程度互いに連動して変化するかを示す指標として重要です。例えば、ある変数が増加するときに他の変数が増加するか減少するかを理解する際に活用されます。

Cov関数には、行または列を基準として共分散を計算する機能があります。また、ベクトル間の共分散を直接計算することもできます。これにより、データ分析や予測モデルの構築で役立つ情報を提供します。


共分散行列とは

共分散行列は、統計学で使われる数学的な概念で、複数の変数の間にどのような関係があるかを示すために使用されます。

例えば、学校のテストで数学の点数と理科の点数を比較するとします。この2つの科目の点数がいつも一緒に高くなったり低くなったりする場合、これらの変数には「正の共分散」があると言えます。逆に、数学の点数が高くなると理科の点数が低くなる場合、「負の共分散」があると考えられます。

共分散は「変数間の相関の方向性」を示しますが、数値の範囲や単位に依存します。そのため、複数の変数間の関係性をまとめて表現するために、行列形式で共分散を整理したものが共分散行列です。

行列の各要素は、それぞれの変数の間の共分散を表しています。例えば、行列の縦軸が「通貨ペアAの価格変動」、横軸が「通貨ペアBの価格変動」の場合、行列の該当箇所には通貨ペアAと通貨ペアBの価格変動の共分散が記録されます。

この行列を使用すると、複数の変数を一度に分析できるようになります。

共分散について

共分散の公式は次のようになります。

共分散(X, Y) = Σ((X_i – 平均X) * (Y_i – 平均Y)) / (n – 1)

ここで:

  • X, Y は2つのデータセットです。例えば、ある期間の通貨ペアAと通貨ペアBの価格変動を示すデータです。
  • X_i, Y_i はそれぞれのデータセットの個々のデータ点です。例えば、1日目の通貨ペアAの価格変動がX_1、通貨ペアBの価格変動がY_1です。
  • 平均X, 平均Y は、それぞれのデータセットの平均値です。
  • Σ は「すべてのデータ点を合計する」ことを意味します。
  • n はデータ点の数です。例えば、10日間分の価格データがあれば、n = 10 です。

公式の意味を簡単に分解すると次のようになります。

  1. まず、それぞれのデータ点から平均値を引きます。
    これは、そのデータが平均値からどれだけ離れているかを計算するためです。例: データセットX = [3, 5, 8] の場合、平均X = (3 + 5 + 8) / 3 = 5.33…
    各データ点について、3 – 5.33…, 5 – 5.33…, 8 – 5.33… を計算します。
  2. XとYそれぞれの「平均からの差」を掛け合わせます。
    これは、XとYが同じ方向に動いている(つまり、正の関係がある)のか、逆方向に動いている(負の関係がある)のかを調べるためです。
  3. すべての掛け合わせた結果を合計します(Σの部分)。
    XとYの関係性を全体的に評価するためです。
  4. 最後に、データの数から1を引いたもので割ります(n – 1)。
    データが少ないときでも正確な結果が得られるようにするためです。

この公式を使うと、2つのデータセットがどの程度連動して動くかを数値で表すことができます。共分散が正であれば、2つのデータセットが同じ方向に動く傾向があることを意味します。共分散が負であれば、逆方向に動く傾向があることを示します。共分散がゼロに近い場合、ほとんど関連性がないと考えられます。

Cov関数の引数について

Cov関数は、2つの形式(バリアント)を持つオーバーロード関数です。


matrix::Cov関数

matrix matrix::Cov(
  const bool    rowvar=true // 観測値の行ベクトルまたは列ベクトル
);

この形式では、行列matrix)の共分散行列を計算します。

  • rowvar
    この引数bool型で、行を観測値(計算対象となる、行列ベクトルの各要素)として扱うか列を観測値として扱うかを指定します。
    • trueを指定した場合、行を観測値と見なし、各列を変数として扱います。
    • falseを指定した場合、列を観測値と見なし、各行を変数として扱います。
      初期値としてtrueが設定されています。

例として、行列内の観測データが行ベクトルとして配置されている場合、この引数を変更することで柔軟な分析が可能になります。


vector::Cov関数

matrix vector::Cov(
  const vector&  b          // 2番目のベクトル
);

この形式では、2つのベクトル間の共分散を計算します。

この引数を使用すると、異なる2つのデータセット間の共分散を計算できます。


Cov関数の戻り値について

Cov関数戻り値は、共分散を計算した結果を格納した行列matrix)です。戻り値の形式と意味について、それぞれのバリアントに基づいて説明します。


matrix::Cov関数の場合

この形式では、計算された共分散行列戻り値として返されます。

例として、rowvar=trueの場合、戻り値行列は元の行列の列間の共分散を表します。一方で、rowvar=falseの場合、戻り値行列は行間の共分散を表します。


vector::Cov関数の場合

この形式では、2つのベクトル間の共分散行列戻り値として返されます。

この戻り値は、2つのベクトルがどの程度連動して変化するかを具体的に示します。


共通点

両形式とも、戻り値として得られる共分散行列は対称性を持つことが特徴です。これは、共分散が順序に依存しないためです(例えば、ベクトルAとベクトルBの共分散は、ベクトルBとベクトルAの共分散と等しい)。

戻り値を利用して、データの傾向や変数間の関係を分析することが可能です。

Cov関数を使ったサンプルコード

//+------------------------------------------------------------------+
//| スクリプトのエントリーポイント                                  |
//+------------------------------------------------------------------+
void OnStart()
{
   // スクリプトが実行された際に呼び出される関数です

   //--- 行列を定義(matrix_aを作成)
   matrix matrix_a = {{3, -2.1}, {1.1, -1}, {0.12, 4.3}};
   // matrix_aの内容をコンソールに出力して確認
   Print("行列 matrix_a: ", matrix_a);

   //--- Cov関数を使用して列ベースで共分散行列を計算
   matrix covariance_cols = matrix_a.Cov(false); // 列を基準に共分散を計算
   Print("列ベースの共分散行列: ", covariance_cols);

   //--- Cov関数を使用して行ベースで共分散行列を計算
   matrix covariance_rows = matrix_a.Cov(); // 行を基準に共分散を計算
   Print("行ベースの共分散行列: ", covariance_rows);

   //--- ベクトルを抽出して共分散行列を計算
   vector vector_a = matrix_a.Col(0); // matrix_aの第1列をベクトルとして抽出
   vector vector_b = matrix_a.Col(1); // matrix_aの第2列をベクトルとして抽出

   // ベクトル間の共分散を計算
   matrix covariance_vectors = vector_a.Cov(vector_b);
   Print("ベクトル間の共分散行列: ", covariance_vectors);

   /*
      実行結果(例):
      行列 matrix_a:
      [[3,-2.1],[1.1,-1],[0.12,4.3]]
      列ベースの共分散行列:
      [[2.144133333333333,-4.286],[-4.286,11.71]]
      行ベースの共分散行列:
      [[13.005,5.355,-10.659],[5.355,2.205,-4.389],[-10.659,-4.389,8.736199999999998]]
      ベクトル間の共分散行列:
      [[2.144133333333333,-4.286],[-4.286,11.71]]
   */
}

サンプルコード解説

このスクリプトでは、matrix型とvector型のデータを使って共分散行列を計算しています。共分散行列は、異なる変数間の連動性(関連性)を数値で表します。例えば、通貨ペアAの価格変動と通貨ペアBの価格変動が互いにどのように関連しているかを確認するのに役立ちます。

計算は以下のステップで進行します。

  1. 行列matrix_aを定義します。
  2. Cov関数を使って行や列を基準にした共分散行列を計算します。
  3. 行列の列をベクトルとして抽出し、Cov関数で2つのベクトル間の共分散を計算します。

行列matrix_aの定義

まず、次の行列matrix_aを定義します。

matrix_a = [[3, -2.1],
            [1.1, -1],
            [0.12, 4.3]]

この行列の各行が観測値を表し、各列が異なる変数(例えば通貨ペアAと通貨ペアBの価格変動)を示します。


列ベースの共分散行列を計算

matrix_a.Cov(false)を呼び出すことで、列を基準に共分散行列を計算します。ここでは、列1(3, 1.1, 0.12)と列2(-2.1, -1, 4.3)の間で計算が行われます。

1. 各列の平均を計算

  • 列1の平均: (3 + 1.1 + 0.12) / 3 = 1.406666...
  • 列2の平均: (-2.1 - 1 + 4.3) / 3 = 0.4

2. 各要素から平均を引く

各列の要素からその列の平均を引きます。

  • 列1: (3 - 1.406666..., 1.1 - 1.406666..., 0.12 - 1.406666...) = (1.593333..., -0.306666..., -1.286666...)
  • 列2: (-2.1 - 0.4, -1 - 0.4, 4.3 - 0.4) = (-2.5, -1.4, 3.9)

3. 共分散を計算

共分散行列要素を計算します。
要素は次のように計算されます。

  • 共分散(列1, 列1): (1.593333...*1.593333... + (-0.306666...)*(-0.306666...) + (-1.286666...)*(-1.286666...)) / 2 = 2.144133...
  • 共分散(列1, 列2): (1.593333...*(-2.5) + (-0.306666...)*(-1.4) + (-1.286666...)*3.9) / 2 = -4.286
  • 共分散(列2, 列2): ((-2.5)*(-2.5) + (-1.4)*(-1.4) + 3.9*3.9) / 2 = 11.71

これにより、共分散行列は以下のようになります。

[[2.144133..., -4.286],
 [-4.286, 11.71]]

行ベースの共分散行列を計算

次に、matrix_a.Cov()を呼び出して行を基準に共分散行列を計算します。ここでは、各行間の共分散を計算します。計算の詳細はステップ2と同様ですが、基準が行に変わる点が異なります。


ベクトル間の共分散を計算

matrix_aの列をベクトルとして抽出し、vector_a(列1)とvector_b(列2)間の共分散を計算します。

ベクトルvector_aとvector_b

  • vector_a: [3, 1.1, 0.12]
  • vector_b: [-2.1, -1, 4.3]

平均と共分散の計算

先ほどと同じ手順で、平均を引き、積を取って平均を計算することで、次の共分散行列が得られます。

[[2.144133..., -4.286],
 [-4.286, 11.71]]

実行結果

上記の計算を実行すると、以下のような結果が得られます。

列ベースの共分散行列

    [[2.144133333333333, -4.286],
     [-4.286, 11.71]]

    行ベースの共分散行列

    [[13.005, 5.355, -10.659],
     [5.355, 2.205, -4.389],
     [-10.659, -4.389, 8.736199999999998]]

    ベクトル間の共分散行列

    [[2.144133333333333, -4.286],
     [-4.286, 11.71]]
    

    補足:共分散を計算するオリジナル定義関数のサンプルコード

    以下はCov関数を使わずに、共分散を計算する場合のオリジナル関数のサンプルコードになります。

    //+------------------------------------------------------------------+
    //| 2つのベクトル間の共分散行列を計算する関数                       |
    //| vector_a: 第1のベクトル                                          |
    //| vector_b: 第2のベクトル                                          |
    //| matrix_c: 結果の共分散行列を格納する変数                         |
    //| 戻り値: 計算が成功した場合はtrue、失敗した場合はfalseを返します  |
    //+------------------------------------------------------------------+
    bool VectorCovariation(const vector& vector_a, const vector& vector_b, matrix& matrix_c)
    {
       //--- ローカル変数を定義
       int i, j; // ループ用のカウンタ変数
       int m = 2; // 共分散行列の次元(2つのベクトルを扱うため固定値2)
       
       //--- ベクトルの長さを取得し、小さい方をnとする
       // ベクトルのサイズが異なる場合でも、短い方の長さに合わせて計算します
       int n = (int)(vector_a.Size() < vector_b.Size() ? vector_a.Size() : vector_b.Size());
       
       //--- データチェック: ベクトルのサイズが1以下の場合、共分散の計算はできない
       if (n <= 1)
          return(false);
       
       //--- 各ベクトルの要素が有効な数値かどうかを確認
       // 無効な数値(NaNなど)が含まれている場合はfalseを返します
       for (i = 0; i < n; i++)
       {
          if (!MathIsValidNumber(vector_a[i]))
             return(false);
          if (!MathIsValidNumber(vector_b[i]))
             return(false);
       }
       
       //--- 共分散計算用の一時行列を作成
       matrix matrix_x(2, n); // 2行n列の行列を作成
       matrix_x.Row(vector_a, 0); // 行列の第1行にvector_aを格納
       matrix_x.Row(vector_b, 1); // 行列の第2行にvector_bを格納
       
       //--- 各ベクトルの平均を計算して保持するベクトルを作成
       vector t = vector::Zeros(m); // 要素がすべて0のベクトルを作成(長さ2)
       
       //--- 平均を計算
       for (i = 0; i < m; i++)
          for (j = 0; j < n; j++)
             t[i] += matrix_x[i][j] / double(n); // 各行の平均を計算してtに格納
       
       //--- 各要素から平均を引く
       // 平均値を引くことで、データを中心化します
       for (i = 0; i < m; i++)
          for (j = 0; j < n; j++)
             matrix_x[i][j] -= t[i];
       
       //--- 共分散行列を計算
       // 初期化: m×mサイズのゼロ行列を作成
       matrix_c = matrix::Zeros(m, m);
       
       // 共分散の計算ロジック
       for (i = 0; i < m; i++)
       {
          for (j = 0; j < n; j++)
          {
             // 各要素に (X - 平均) / (n-1) を掛ける
             double v = matrix_x[i][j] / (n - 1);
             for (int i_ = i; i_ < m; i_++)
                matrix_c[i][i_] += v * matrix_x[i_][j]; // 結果を共分散行列に加算
          }
       }
       
       //--- 行列を対称にする(数値誤差を防ぐため)
       // 対角成分以外の値を対称にする処理
       for (i = 0; i < m - 1; i++)
          for (j = i + 1; j < m; j++)
             matrix_c[j][i] = matrix_c[i][j];
       
       //--- 計算成功を示すtrueを返す
       return(true);
    }
    

    コード解説1

    //+------------------------------------------------------------------+
    //| 2つのベクトル間の共分散行列を計算する関数                       |
    //| vector_a: 第1のベクトル                                          |
    //| vector_b: 第2のベクトル                                          |
    //| matrix_c: 結果の共分散行列を格納する変数                         |
    //| 戻り値: 計算が成功した場合はtrue、失敗した場合はfalseを返します  |
    //+------------------------------------------------------------------+
    bool VectorCovariation(const vector& vector_a, const vector& vector_b, matrix& matrix_c)
    {
       //--- ローカル変数を定義
       int i, j; // ループ用のカウンタ変数
       int m = 2; // 共分散行列の次元(2つのベクトルを扱うため固定値2)
       
       //--- ベクトルの長さを取得し、小さい方をnとする
       // ベクトルのサイズが異なる場合でも、短い方の長さに合わせて計算します
       int n = (int)(vector_a.Size() < vector_b.Size() ? vector_a.Size() : vector_b.Size());
       
       //--- データチェック: ベクトルのサイズが1以下の場合、共分散の計算はできない
       if (n <= 1)
          return(false);
       

    この部分のコードは、2つのベクトル間の共分散行列を計算するための準備を行っています。共分散を計算する際に必要な入力データのチェックや、処理の基礎となるローカル変数の設定が含まれています。


    関数の定義と仮引数

    この関数の名前はVectorCovariationで、以下の3つの引数を受け取ります。

    1. vector_a
    2. vector_b
    3. matrix_c

    ローカル変数の定義

    関数内で計算を進めるためのローカル変数を定義しています。

    1. ij
      • これらはループ処理用のカウンタ変数です。iベクトルの行を、jは列を処理する際に使用されます。
    2. m
    3. n
    int n = (int)(vector_a.Size() < vector_b.Size() ? vector_a.Size() : vector_b.Size());
    

    この部分のコードは、ベクトルvector_aとvector_bのサイズ(要素数)を比較し、短い方のサイズをnに設定しています。

    まず、vector_a.Size()とvector_b.Size()は、それぞれのベクトル要素数を取得します。例えば、vector_aが要素数3、vector_bが要素数5の場合、この値はそれぞれ3と5になります。

    次に、三項演算子 ? : を使用しています。vector_a.Size() < vector_b.Size() という条件を評価し、条件がtrue(vector_aが短い)の場合はvector_a.Size()を返し、false(vector_bが短い)の場合はvector_b.Size()を返します。例えば、条件 3 < 5 がtrueなので、vector_a.Size()の値3が選ばれます。

    最後に、(int) のキャストを行っています。返されたサイズを明示的に整数型(int)に変換します。通常、Size()は整数型を返しますが、他の型に変わる可能性を防ぐため、明示的にキャストしています。

    最終的に、この式は2つのベクトルのサイズのうち小さい方の値をnに格納します。この処理により、異なるサイズのベクトル間で安全に共分散を計算する準備が整います。


    データチェック

    この部分では、入力データが共分散を計算する条件を満たしているかを確認します。

    1. ベクトルの長さが1以下の場合
      • ベクトル要素数が1以下の場合は共分散を計算できません。共分散はデータの「変動」を計算するため、最低でも2つ以上のデータが必要です。
      • この条件を満たさない場合、falseを返して関数の処理を終了します。

    コード解説2

      //--- 各ベクトルの要素が有効な数値かどうかを確認
       // 無効な数値(NaNなど)が含まれている場合はfalseを返します
       for (i = 0; i < n; i++)
       {
          if (!MathIsValidNumber(vector_a[i]))
             return(false);
          if (!MathIsValidNumber(vector_b[i]))
             return(false);
       }

    この部分のコードは、入力された2つのベクトルvector_aとvector_bが、有効な数値データで構成されているかを確認する処理を行っています。共分散を計算するためには、データが数値であることが必須であり、このチェックによってデータの品質を保証しています。

    まず、ループを使用してベクトルの各要素を順番に確認します。変数iはベクトルインデックス(位置)を示しており、インデックスiが0からn-1までの範囲で繰り返し処理を行います。

    次に、MathIsValidNumber関数を使って、各要素が有効な数値であるかどうかを調べます。この関数は、値が無効(例えば、NaNや無限大など)の場合にfalseを返します。チェックは以下のように行われています。

    • vector_aのi番目の要素が無効な数値である場合、関数はfalseを返して終了します。これにより、以降の処理をスキップし、不正なデータに基づいて計算されることを防ぎます。
    • vector_bのi番目の要素についても同様にチェックを行います。

    これにより、ベクトル内に少しでも無効な数値が含まれている場合は、その場で処理を停止し、共分散の計算が実行されないようにしています。このデータチェックは、信頼できる結果を得るための重要なステップです。

    コード解説3

     //--- 共分散計算用の一時行列を作成
       matrix matrix_x(2, n); // 2行n列の行列を作成
       matrix_x.Row(vector_a, 0); // 行列の第1行にvector_aを格納
       matrix_x.Row(vector_b, 1); // 行列の第2行にvector_bを格納
       
       //--- 各ベクトルの平均を計算して保持するベクトルを作成
       vector t = vector::Zeros(m); // 要素がすべて0のベクトルを作成(長さ2)
       

    この部分のコードは、共分散を計算するための一時的な行列を作成し、入力ベクトルをその行列に配置する処理を行っています。


    まず、2行n列の一時行列matrix_xを作成します。ここで2行は、2つのベクトルvector_aとvector_bを格納するための行であり、n列はベクトル要素数を表します。この行列共分散の計算過程で使用される中間的なデータ構造です。

    次に、Row関数を使用して、ベクトルvector_aをmatrix_xの第1行に格納します。この処理により、vector_aの全要素行列matrix_xの第1行に対応付けられます。

    続いて、同じくRow関数を使用して、ベクトルvector_bをmatrix_xの第2行に格納します。この処理により、vector_bの全要素行列matrix_xの第2行に対応付けられます。

    次に、各ベクトルの平均値を計算して保持するためのベクトルtを作成します。このベクトルは、長さmの要素を持ち、vector::Zeros関数を使用して初期化されます。

    Zeros関数は、すべての要素が0に設定された新しいベクトルを作成します。ここでmは、共分散行列の次元であり、常に2です。

    この処理により、2つのベクトル行列形式でまとめ、それぞれの平均値を計算して記録する準備が整います。平均値は、データを中心化するために重要であり、共分散の計算における次のステップで使用されます。行列形式にすることで、計算の効率性とデータの整列性を確保しています。ベクトルtは、計算の中間結果を記録するための重要な役割を果たします。

    コード解説4

       //--- 平均を計算
       for (i = 0; i < m; i++)
          for (j = 0; j < n; j++)
             t[i] += matrix_x[i][j] / double(n); // 各行の平均を計算してtに格納

    この部分のコードは、一時行列matrix_xの各行に対応する平均値を計算し、その結果をベクトルtに格納する処理を行っています。


    まず、二重ループを使用して行列matrix_xの全要素を順に処理します。

    外側のループでは、変数iが0からm-1(ここではm=2なので、0と1)までの範囲を取り、行列matrix_xの各行を順番に選択します。i=0のときは第1行(vector_aに対応)、i=1のときは第2行(vector_bに対応)を処理します。

    内側のループでは、変数jが0からn-1までの範囲を取り、行列matrix_xの各行の列を順に選択します。これは、各行の全要素に対して計算を行うための処理です。

    ループ内では、matrix_x[i][j]の値を合計し、その結果をベクトルtのi番目の要素に加算します。この際、値をnで割ることで平均値を計算しています。ここで、double型キャストすることで、整数割り算による誤差を防ぎます。

    例えば、matrix_xの第1行が[3.0, 1.5, 2.5]でn=3の場合、次の計算が行われます。 t[0] = (3.0 / 3) + (1.5 / 3) + (2.5 / 3) = 2.333…

    この処理を各行に対して繰り返し、ベクトルtには次のような値が格納されます。

    • t[0]: 第1行(vector_aに対応)の平均値
    • t[1]: 第2行(vector_bに対応)の平均値

    このように、各行の平均値を計算することで、次のステップで行うデータの中心化(各値から平均を引く処理)の準備が整います。この中心化は、共分散を計算する上で欠かせないプロセスです。

    コード解説5

       //--- 各要素から平均を引く
       // 平均値を引くことで、データを中心化します
       for (i = 0; i < m; i++)
          for (j = 0; j < n; j++)
             matrix_x[i][j] -= t[i];
       

    この部分のコードは、一時行列matrix_xの各要素から、それぞれの行に対応する平均値を引き、データを中心化する処理を行っています。中心化とは、データをその平均値からの偏差に置き換えることで、平均が0になるようにすることを意味します。


    まず、外側のループでは、変数iが0からm-1(ここではm=2なので、0と1)までの範囲を取り、行列matrix_xの各行を順番に選択します。i=0のときは第1行(vector_aに対応)、i=1のときは第2行(vector_bに対応)を処理します。

    内側のループでは、変数jが0からn-1までの範囲を取り、行列matrix_xの各行の各列要素を順番に処理します。

    処理の中で、matrix_x[i][j] -= t[i]という演算が行われます。これは、matrix_xのi行j列の要素から、その行の平均値t[i]を引く操作です。この操作によって、各要素は「平均からの偏差」に変換されます。

    例えば、matrix_xの第1行が[3.0, 1.5, 2.5]で、対応する平均値t[0]が2.333…の場合、次の計算が行われます。

    • matrix_x[0][0] = 3.0 – 2.333… = 0.666…
    • matrix_x[0][1] = 1.5 – 2.333… = -0.833…
    • matrix_x[0][2] = 2.5 – 2.333… = 0.166…

    この処理を各行に対して繰り返すことで、行列matrix_xは中心化されたデータを含む行列に変換されます。中心化されたデータは、共分散を計算するための前提条件です。この操作によって、データの相対的な変動だけを分析できるようになります。具体的には、データの位置(平均値)に影響されず、変数間の相関を適切に評価するための準備が整います。

    コード解説6

     //--- 共分散行列を計算
       // 初期化: m×mサイズのゼロ行列を作成
       matrix_c = matrix::Zeros(m, m);
       
       // 共分散の計算ロジック
       for (i = 0; i < m; i++)
       {
          for (j = 0; j < n; j++)
          {
             // 各要素に (X - 平均) / (n-1) を掛ける
             double v = matrix_x[i][j] / (n - 1);
             for (int i_ = i; i_ < m; i_++)
                matrix_c[i][i_] += v * matrix_x[i_][j]; // 結果を共分散行列に加算
          }
       }

    この部分のコードは、中心化されたデータを基に共分散行列を計算する処理を行っています。共分散行列は、変数間の共分散行列形式で表したもので、各要素は2つの変数間の連動性を数値で示します。


    まず、共分散行列matrix_cを初期化します。この行列はm×m(ここでは2×2)のゼロ行列として作成されます。matrix::Zeros(m, m)は、すべての要素が0の新しい行列を作成します。共分散の計算結果を加算していくための土台として必要です。

    次に、二重ループを使用して共分散行列の各要素を計算します。

    外側のループでは、変数iが0からm-1までの範囲を取り、共分散行列matrix_cの行を選択します。このループは、行列の行を処理するためのものです。

    内側のループでは、変数jが0からn-1までの範囲を取り、一時行列matrix_xの各列を選択します。このループは、中心化されたデータmatrix_xの列を処理します。

    内側ループの中で、matrix_x[i][j] / (n – 1)という計算が行われます。この計算では、中心化されたデータ(matrix_x[i][j])をサンプル数n-1で割ることで、共分散を求めるための基礎的な値を作成しています。この値は変数vに格納されます。

    さらに、最も内側のループで、変数i_をiからm-1までの範囲でループさせます。このループは、共分散行列の対称性を利用して効率よく計算を行うためのものです。

    最終的に、共分散行列要素matrix_c[i][i_]に、vとmatrix_x[i_][j]の積を加算します。この操作を繰り返すことで、共分散行列の各要素が徐々に計算され、完成します。

    例えば、以下のような処理が行われます。

    • i=0, i_=0のとき、matrix_c[0][0]にv * matrix_x[0][j]が加算されます。
    • i=0, i_=1のとき、matrix_c[0][1]にv * matrix_x[1][j]が加算されます。

    これにより、共分散行列の上三角部分が計算され、変数間の共分散を正確に表現する行列が完成します。この計算ロジックは、中心化されたデータを基に、データ間の相関を評価するための重要なステップです。

    コード解説7

    //--- 行列を対称にする(数値誤差を防ぐため)
       // 対角成分以外の値を対称にする処理
       for (i = 0; i < m - 1; i++)
          for (j = i + 1; j < m; j++)
             matrix_c[j][i] = matrix_c[i][j];
       
       //--- 計算成功を示すtrueを返す
       return(true);
    }
    

    この部分のコードは、共分散行列の対称性を保証する処理と、計算が成功したことを示す戻り値を返す処理を行っています。


    まず、共分散行列matrix_cの対称性を強制的に確保します。共分散行列は本来対称行列であり、行列要素matrix_c[i][j]matrix_c[j][i]は常に同じ値を持つべきです。しかし、計算の過程で発生するわずかな数値誤差が原因で、この性質が崩れる場合があります。

    この問題を防ぐため、二重ループを使用して行列の上三角部分の値を下三角部分にコピーします。

    外側のループでは、変数iが0からm-2までの範囲を取り、対称性を確保する行列の行を選択します。

    内側のループでは、変数jがi+1からm-1までの範囲を取り、対称性を調整する列を選択します。このループは、行列の上三角部分の要素を処理します。

    処理の中で、matrix_c[j][i] = matrix_c[i][j]を実行します。これは、上三角部分にある値matrix_c[i][j]を下三角部分の対応する位置matrix_c[j][i]にコピーする操作です。この操作により、行列matrix_cの対称性が保証されます。


    最後に、return(true)を実行して関数を終了します。この戻り値trueは、共分散行列の計算が正常に完了したことを示します。これにより、関数を呼び出した側のプログラムは、計算結果を安全に利用できることが確認できます。


    この部分の処理は、共分散行列の正確性と一貫性を保証する重要な役割を果たします。特に、行列の対称性を確保することで、後続の計算や分析が適切に行えるようになります。

    タイトルとURLをコピーしました