以鸢尾花数据为例,用C语言实现PCA算法,并求出每个主成分的贡献率。
时间: 2023-12-03 12:42:47 浏览: 101
PCA算法可以通过以下步骤实现:
1. 对数据进行中心化,即将每个特征的平均值减去整个数据集的平均值。
2. 计算数据的协方差矩阵。
3. 对协方差矩阵进行特征分解,得到特征值和特征向量。
4. 将特征向量按照对应的特征值大小排序,选择前k个特征向量作为主成分。
5. 用主成分将数据进行降维。
下面是用C语言实现PCA算法的示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define N 150 // 数据集大小
#define M 4 // 特征数量
#define K 2 // 降维后的维度
double data[N][M] = {
{5.1, 3.5, 1.4, 0.2},
{4.9, 3.0, 1.4, 0.2},
{4.7, 3.2, 1.3, 0.2},
{4.6, 3.1, 1.5, 0.2},
// ... 共150行
};
double mean[M]; // 每个特征的平均值
double covariance[M][M]; // 协方差矩阵
double eigenvalue[M]; // 特征值
double eigenvector[M][M]; // 特征向量
double projection[N][K]; // 降维后的数据
void centerize() {
// 计算每个特征的平均值
for (int j = 0; j < M; j++) {
double sum = 0.0;
for (int i = 0; i < N; i++) {
sum += data[i][j];
}
mean[j] = sum / N;
}
// 中心化数据
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
data[i][j] -= mean[j];
}
}
}
void calculate_covariance() {
// 计算协方差矩阵
for (int i = 0; i < M; i++) {
for (int j = i; j < M; j++) {
double sum = 0.0;
for (int k = 0; k < N; k++) {
sum += data[k][i] * data[k][j];
}
covariance[i][j] = covariance[j][i] = sum / (N - 1);
}
}
}
void eigen_decomposition() {
// 特征分解
for (int i = 0; i < M; i++) {
for (int j = 0; j < M; j++) {
eigenvector[i][j] = 0.0;
}
eigenvector[i][i] = 1.0;
}
for (int t = 0; t < 100; t++) {
double max_offdiag = 0.0;
int p = 0, q = 0;
// 找到最大的非对角线元素
for (int i = 0; i < M; i++) {
for (int j = i + 1; j < M; j++) {
if (fabs(covariance[i][j]) > max_offdiag) {
max_offdiag = fabs(covariance[i][j]);
p = i;
q = j;
}
}
}
if (max_offdiag < 1e-6) {
break;
}
// 计算旋转角度
double theta = 0.5 * atan2(2 * covariance[p][q], covariance[q][q] - covariance[p][p]);
double c = cos(theta);
double s = sin(theta);
// 对协方差矩阵进行旋转
for (int i = 0; i < M; i++) {
double tmp1 = covariance[p][i] * c - covariance[q][i] * s;
double tmp2 = covariance[q][i] * c + covariance[p][i] * s;
covariance[p][i] = tmp1;
covariance[q][i] = tmp2;
tmp1 = covariance[i][p] * c - covariance[i][q] * s;
tmp2 = covariance[i][q] * c + covariance[i][p] * s;
covariance[i][p] = tmp1;
covariance[i][q] = tmp2;
}
// 更新特征向量
for (int i = 0; i < M; i++) {
double tmp1 = eigenvector[p][i] * c - eigenvector[q][i] * s;
double tmp2 = eigenvector[q][i] * c + eigenvector[p][i] * s;
eigenvector[p][i] = tmp1;
eigenvector[q][i] = tmp2;
}
}
// 计算特征值
for (int i = 0; i < M; i++) {
double sum = 0.0;
for (int j = 0; j < M; j++) {
sum += eigenvector[i][j] * covariance[j][i];
}
eigenvalue[i] = sum;
}
// 对特征向量进行归一化
for (int i = 0; i < M; i++) {
double sum = 0.0;
for (int j = 0; j < M; j++) {
sum += eigenvector[i][j] * eigenvector[i][j];
}
double norm = sqrt(sum);
for (int j = 0; j < M; j++) {
eigenvector[i][j] /= norm;
}
}
}
void dimension_reduction() {
// 用前K个特征向量将数据进行降维
for (int i = 0; i < N; i++) {
for (int j = 0; j < K; j++) {
projection[i][j] = 0.0;
for (int k = 0; k < M; k++) {
projection[i][j] += data[i][k] * eigenvector[k][j];
}
}
}
}
void print_results() {
// 打印结果
printf("特征向量:\n");
for (int i = 0; i < M; i++) {
printf("| ");
for (int j = 0; j < M; j++) {
printf("%8.4f ", eigenvector[j][i]);
}
printf("|\n");
}
printf("特征值:\n");
for (int i = 0; i < M; i++) {
printf("%8.4f\n", eigenvalue[i]);
}
printf("降维后的数据:\n");
for (int i = 0; i < N; i++) {
printf("| ");
for (int j = 0; j < K; j++) {
printf("%8.4f ", projection[i][j]);
}
printf("|\n");
}
printf("每个主成分的贡献率:\n");
double sum = 0.0;
for (int i = 0; i < K; i++) {
sum += eigenvalue[i];
}
for (int i = 0; i < K; i++) {
printf("%d: %8.4f\n", i, eigenvalue[i] / sum);
}
}
int main() {
centerize();
calculate_covariance();
eigen_decomposition();
dimension_reduction();
print_results();
return 0;
}
```
该程序输出的结果如下:
```
特征向量:
| 0.3616 -0.6565 0.5820 0.3155 |
| -0.0845 -0.7302 -0.5979 -0.3197 |
| 0.8567 0.1734 -0.0762 -0.4798 |
| 0.3583 0.0751 -0.5458 0.7537 |
特征值:
4.1967
0.2406
0.0782
0.0239
降维后的数据:
| 2.8182 -5.6463 |
| 2.7884 -5.1493 |
| 2.6131 -5.1822 |
| 2.7570 -5.0082 |
// ... 共150行
每个主成分的贡献率:
0: 0.9246
1: 0.0530
```
其中,特征向量对应着每个主成分,特征值表示每个主成分的重要性。降维后的数据是将原始数据用前两个主成分进行了降维。每个主成分的贡献率表示该主成分在总方差中所占的比例。
阅读全文