特征库的主成分分析

Chr*_*ris 6 c++ pca eigen

我正在尝试使用Eigen从C++中的数据集计算2个主要主成分.

我现在这样做的方法是将数据标准化[0, 1],然后将均值居中.之后,我计算协方差矩阵并对其运行特征值分解.我知道SVD更快,但我对计算组件感到困惑.

这是关于我如何做的主要代码(traindata我的MxN大小的输入矩阵在哪里):

Eigen::VectorXf normalize(Eigen::VectorXf vec) {
  for (int i = 0; i < vec.size(); i++) { // normalize each feature.
      vec[i] = (vec[i] - minCoeffs[i]) / scalingFactors[i];
  }
  return vec;
}

// Calculate normalization coefficients (globals of type Eigen::VectorXf). 
maxCoeffs = traindata.colwise().maxCoeff();
minCoeffs = traindata.colwise().minCoeff();
scalingFactors = maxCoeffs - minCoeffs;

// For each datapoint.
for (int i = 0; i < traindata.rows(); i++) { // Normalize each datapoint.
  traindata.row(i) = normalize(traindata.row(i));
}

// Mean centering data.
Eigen::VectorXf featureMeans = traindata.colwise().mean();
Eigen::MatrixXf centered = traindata.rowwise() - featureMeans;

// Compute the covariance matrix.
Eigen::MatrixXf cov = centered.adjoint() * centered;
cov = cov / (traindata.rows() - 1);

Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eig(cov);
// Normalize eigenvalues to make them represent percentages.
Eigen::VectorXf normalizedEigenValues =  eig.eigenvalues() / eig.eigenvalues().sum();


// Get the two major eigenvectors and omit the others.
Eigen::MatrixXf evecs = eig.eigenvectors();
Eigen::MatrixXf pcaTransform = evecs.rightCols(2);


// Map the dataset in the new two dimensional space.
traindata = traindata * pcaTransform;
Run Code Online (Sandbox Code Playgroud)

这段代码的结果是这样的:

在此输入图像描述

为了确认我的结果,我尝试了同样的WEKA.所以我做的是按顺序使用normalize和center过滤器.然后主成分过滤并保存+绘制输出.结果是这样的:

在此输入图像描述

从技术上讲,我应该做同样的事,但结果是如此不同.谁能看出我犯了错误?

gga*_*ael 5

当缩放为0,1时,您修改了局部变量,vec却忘记了更新traindata

而且,可以通过以下方式更轻松地完成此操作:

RowVectorXf minCoeffs = traindata.colwise().maxCoeff();
RowVectorXf minCoeffs = traindata.colwise().minCoeff();
RowVectorXf scalingFactors = maxCoeffs - minCoeffs;
traindata = (traindata.rowwise()-minCoeffs).array().rowwise() / scalingFactors.array();
Run Code Online (Sandbox Code Playgroud)

也就是说,使用行向量和数组特征。

我还要补充一点,对称特征值分解实际上比SVD更快。在这种情况下,SVD的真正优势在于,它避免了对输入进行平方运算,但是由于您的输入数据已归一化并居中,而且您只关心最大的特征值,因此这里没有精度问题。


Chr*_*ris 2

原因是 Weka 对数据集进行了标准化。这意味着它将每个特征的方差缩放到单位方差。当我这样做时,情节看起来是一样的。从技术上讲,我的方法也是正确的。