OpenCVで主成分分析をしてみた

主成分分析とは

主成分分析:PCA (Principal Component Analysis)は,多次元データの解析法の一種で,多次元空間中のデータ分布のうち,最も分散の大きくなる方向から順に基底を取っていく手法です.これをすることにより,データにおける主な変化の傾向を知ることができます.具体的にはいろんなところ(朱鷺の杜Wiki , タコでもわかる主成分分析 , etc.)で紹介されているので,ここでは割愛します.

主成分分析をやるには

大量の高次元ベクトルに対して上記のように分散を計算していくのは手計算では無理です.普通はmatlabやRを使いますが,画像処理屋はOpenCVを使って解析をします.(僕は主に,自前で実装したIncremental PCAを使っているので,以下のコードを実際には使っていません.あと,ちゃんとしたデータに対して動作確認もしてないので,以下のコードを使うのは自己責任でお願いします.)
このコードは,C++とOpenCVを使って,200次元のデータ1000個に対して主成分分析を行う例です.この例では,主成分分析後,上位3次元の基底に着目し,200次元のデータを3次元の空間へ投影した時の座標を出力します.また,各基底がどのくらい強くその分布を表しているかを意味する,累積寄与率も計算して出力しています.入力データは,スペースで区切られた200次元,1000個のベクトルです.

#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <fstream>
#include <iomanip>
int main(){
	const int DIM=200; // 200次元
	const int SAMPLES=1000; // 1000サンプル
	const int RDIM=3; // 圧縮後3次元
	cv::Mat src(SAMPLES,DIM,CV_32FC1);
	cv::Mat result; // DIMとSAMPLESのうち小さい方次元xサンプル数次元
	double val;
	std::ifstream ifs("data.txt");
	for(int j=0;j<SAMPLES;j++){
		for(int i=0;i<DIM;i++){
			ifs >> val;
			((float*)src.data)[j*src.cols+i]=val;
		}
	}
	cv::PCA pca(src,cv::Mat(),CV_PCA_DATA_AS_ROW,RDIM);
	result=pca.project(src);
	for(int j=0;j<SAMPLES;j++){
		for(int i=0;i<RDIM;i++){ // 上位RDIM次元だけを表示
			std::cout << std::dec << ((float*)result.data)[j*result.cols+i] << ",";
		}
		std::cout << std::endl;
	}
	cv::Mat evalues=pca.eigenvalues;
	float sum=0.0f;
	for(int i=0;i<pca.eigenvalues.rows;i++){
		sum+=((float*)evalues.data)[i];
	}
	float contribution=0.0f;
	for(int i=0;i<RDIM;i++){// 上位RDIM次元の寄与率を計算
		contribution+=((float*)evalues.data)[i] / sum;
		std::cout << i+1 << "次元の累積寄与率:" << contribution << std::endl;
	}
	return 0;
}

このように,C++/OpenCVで簡単に主成分分析をすることができます.

「OpenCVで主成分分析をしてみた」への2件のフィードバック

コメントする