スポンサーリンク

主成分分析(PCA)の計算をする前にデータを標準化しないといけないらしい

厳密には、したほうがいい場合としないほうがいい場合があるらしい。

標準化の式は以下。各値から値全体の平均を引き、その値を標準偏差で割る。これをすべての値に対して行う。

Excelで計算

エクセルにはSTANDARDIZEという関数がある。ただしこれを使うためには平均と標準偏差をそれぞれ別途計算する必要がある。

検証

自前実装したコードと上記Excelで半自動計算したものと比較。同じ値が出ている。

サンプルコード

#include <iostream>
#include <vector>
#include <array>

using vector3f = std::vector<std::array<float, 3>>;

//! @brief データの平均を求める
//! @param [in] vec データの配列
//! @return 各要素の平均
std::array<float, 3> Average(const vector3f& vec) {

  // 初期化
  std::array<float, 3> ave;
  ave[0] = 0;
  ave[1] = 0;
  ave[2] = 0;

  // 各要素平均
  for (size_t i = 0; i < vec.size(); i++) {
    ave[0] += vec[i][0];
    ave[1] += vec[i][1];
    ave[2] += vec[i][2];
  }
  ave[0] /= vec.size();
  ave[1] /= vec.size();
  ave[2] /= vec.size();

  return ave;

}

      
//分散
std::array<float, 3> Distributed(const std::array<float, 3>& average, const vector3f& vec) {
  int n = vec.size();
  std::array<float, 3> s2{ 0,0,0 };
  for (int j = 0; j < 3; j++) {
    for (const auto& v : vec) {
      s2[j] += std::pow(v[j] - average[j], 2);
    }
    s2[j] = 1.f / n * s2[j];
  }
  return s2;
}

      
//標準偏差
std::array<float, 3> StandardDeviation(const std::array<float, 3>& average, const vector3f& vec) {

  std::array<float, 3> d = Distributed(average, vec);
  d[0] = sqrt(d[0]);
  d[1] = sqrt(d[1]);
  d[2] = sqrt(d[2]);

  return d;
}

      
//標準化 平均を引いて標準偏差で割る
// average 平均
// sd 標準偏差
void Standardization(vector3f& src, const std::array<float, 3>& average, const std::array<float, 3>& sd) {
  for (auto&& p : src) {
    p[0] = (p[0] - average[0]) / sd[0];
    p[1] = (p[1] - average[1]) / sd[1];
    p[2] = (p[2] - average[2]) / sd[2];
  }
}

int main()
{
  vector3f data;

  data.push_back({ -1.841658711,0.324050009,1.041258931 });
  data.push_back({-1.449076772,0.431593835,0.987673104 });
  data.push_back({-1.04681015,0.415599823,1.049820662 });
  data.push_back({-0.646572888,0.42549479,1.087714672 });
  data.push_back({-0.25920701,0.599574149,0.971796691 });
  data.push_back({ 0.149769783,0.497985959,1.114130974 });
  data.push_back({-1.883069754,0.6849733,1.249212146 });
  data.push_back({-1.481496215,0.677821219,1.303076267 });
  data.push_back({-1.083532453,0.716715276,1.313803315 });


  std::array<float, 3> _s = Average(data);
  std::array<float, 3> sd = StandardDeviation(_s, data);

  Standardization(data, _s, sd);

  for (size_t i = 0; i < data.size(); i++) {
    printf("%lf , %lf , %lf\n", data[i][0], data[i][1], data[i][2]);
  }

}

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: