使用特征库进行主成分分析
Principal Component Analysis with Eigen Library
我正在尝试使用 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 进行了同样的尝试。所以我所做的是按此顺序使用归一化和中心过滤器。然后主成分过滤并保存+绘制输出。结果是这样的:
从技术上讲,我应该做同样的事情,但结果却大不相同。谁能看看我有没有弄错?
缩放到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 的真正优势在于它避免了对条目进行平方,但由于您的输入数据已标准化并居中,并且您只关心最大的特征值,因此这里没有准确性问题。
原因是 Weka 标准化了 数据集。这意味着它将每个特征的方差缩放到单位方差。当我这样做时,情节看起来是一样的。从技术上讲,我的方法也是正确的。
我正在尝试使用 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 进行了同样的尝试。所以我所做的是按此顺序使用归一化和中心过滤器。然后主成分过滤并保存+绘制输出。结果是这样的:
从技术上讲,我应该做同样的事情,但结果却大不相同。谁能看看我有没有弄错?
缩放到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 的真正优势在于它避免了对条目进行平方,但由于您的输入数据已标准化并居中,并且您只关心最大的特征值,因此这里没有准确性问题。
原因是 Weka 标准化了 数据集。这意味着它将每个特征的方差缩放到单位方差。当我这样做时,情节看起来是一样的。从技术上讲,我的方法也是正确的。