Я написал C ++ версию этот Функция Matlab для вычисления PCA (обратите внимание, что здесь данные по столбцам, как в исходном коде Matlab). Если вы заинтересованы:
U
полученная матрица вращенияlams
являются собственными значениями x
Utmu
это просто U.t()*mu
x
это матрица данныхnPCs
количество основных компонентов, которые мы хотим сохранитьЭто мой код на C ++ (не стесняйтесь его просматривать):
template <typename T>
void cc::relja_PCA(T &U, T &lams, T &mu, T &Utmu, const T &x, size_t nPCs, const bool substractMean){
int nPoints = x.cols;
int nDims = x.rows;
if(nPCs <= 0)
nPCs = nDims;
if(substractMean){
cv::reduce(x,mu, 1, CV_REDUCE_AVG);
for(int i=0; i<nPoints; i++){
x.col(i) = x.col(i) - mu;
}
}
else
mu = cv::Mat::zeros(1, nDims, x.type());
bool doDual;
T X2;
if(nDims<=nPoints){
doDual = false;
cv::mulTransposed(x,X2, false);
}
else{
doDual = true;
cv::mulTransposed(x, X2, true);
}
X2 /= (nPoints-1);
cv::eigen(X2, lams, U);
U = U.t();//save only the first nPCs elements of L, which is already a vector
if(nPCs>0 && nPCs<X2.rows){
lams(cv::Range(0, nPCs), cv::Range(0, lams.cols)).copyTo(lams);
U(cv::Range(0,U.rows),cv::Range(0,nPCs)).copyTo(U);
}
if (doDual){
cv::Mat1f diag = lams.clone();
for(int i=0; i<diag.rows; i++)
diag.at<float>(i,1) = diag.at<float>(i,1) > 1e-9 ? diag.at<float>(i,1) : 1e-9;
cv::sqrt(diag, diag);
diag = 1.0f/diag;
diag = cv::Mat::diag(diag);
U = x * (U * diag / std::sqrt(nPoints-1)) ;
}
Utmu = U.t() * mu;
}
Функция вызывается с помощью:
//given some nPCs
cv::Mat1f U, lams, mu, Utmu;
cc::relja_PCA(U, lams, mu, Utmu, mat, nPCs);
И проекция вектора причудливого столбца feat
сделано с:
feat = U.t()*feat - Utmu; //or equivalently feat = U.t() * (feat- mu);
У меня есть 2 вопроса:
U
в cv::eigen(X2, lams, U);
это транспонированная версия [U, L]= eigs(X2, nPCs);
? Как видите, чтобы гарантировать те же результаты исходного кода, я должен U=U.t();
, Зачем? Я заметил это во время тестирования кода с игрушечной матрицей 5×4 и nPCs = 3.U
был напротив w.r.t. те из Matlab.Задача ещё не решена.
Других решений пока нет …