【问题标题】:Principal Component Analysis with Eigen Library使用特征库进行主成分分析
【发布时间】:2016-02-05 12:24:43
【问题描述】:

我正在尝试使用 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;

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

为了确认我的结果,我对 WEKA 进行了同样的尝试。所以我所做的是按这个顺序使用归一化和中心过滤器。然后主成分过滤并保存+绘制输出。结果是这样的:

从技术上讲,我应该做同样的事情,但结果却如此不同。谁能看看我是不是弄错了?

【问题讨论】:

  • 补充一点:我很确定 WEKA 正在使用 SVD。但这不应该解释结果的不同还是?
  • 我知道这个问题已经过时了,但是你有没有机会知道你在这个实现中使用了哪篇论文(或其他来源)?
  • 我想我只是在 Wikipedia 和通过搜索找到的多个其他页面上查找了它。但不是科学论文。但是,如果您需要更可靠的来源,我相信您可以在大量的数学/统计/数据分析书籍中找到该过程。
  • 我确实在寻找这个特定的来源。感谢您的快速回复。

标签: c++ eigen pca


【解决方案1】:

缩放到 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();

即使用行向量和数组特征。

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

【讨论】:

  • 这是一个错误,在我的大代码中,我做了一个函数调用,它按如下值返回:traindata.row(i) = normalize(traindata.row(i));。在这里也更改了它以确保没有错误。感谢您简化代码,我猜想这是可能的。你能看到另一个问题吗?
  • 另一个问题,当我运行您的代码时,我的编译器告诉我“与‘operator/’不匹配”。我有 Eigen3,似乎没有按行划分或?
  • 如果你有 1 个功能 max = min,这将除以零,对吗?
  • 对,你需要将scalingFactors中的零替换为一。
【解决方案2】:

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

【讨论】:

猜你喜欢
  • 2013-10-21
  • 2016-01-16
  • 2016-02-22
  • 2011-06-26
  • 2013-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多