计算方法实验5:对鸢尾花数据集进行主成分分析(PCA)并可视化

任务

iris数据集包含150条数据,从iris.txt读取,每条数据有4个属性值和一个标签(标签取值为0,1,2)。要求对这150个4维数据进行PCA,可视化展示这些数据在前两个主方向上的分布,其中不同标签的数据需用不同的颜色或形状加以区分。

算法

m个n维数据向量去中心化后(各向量的每个维度减去这个维度在所有向量上均值),按列排列构成矩阵 X n × m \mathbf{X}_{n\times m} Xn×m,计算协方差矩阵 V a r n × n = 1 m X X T \mathbf{Var}_{n\times n}= \frac{1}{m}\mathbf{XXT} Varn×n=m1XXT的特征值,选取最大两个特征值对应的特征向量构成矩阵 P 2 × n \mathbf{P}_{2\times n} P2×n,则 Y 2 × m = P X \mathbf{Y}_{2\times m}=\mathbf{PX} Y2×m=PX即PCA后的结果,也就是把四维数据压缩为二维,每个数据对应二维平面上的一个点。
对PCA的详解,可以参考这篇文章;关于PCA与奇异值分解的联系,可以参考这篇文章;关于如何用C++求矩阵特征值(Jacobi方法)和特征向量及对矩阵进行奇异值分解,可以参考这篇文章。

代码

C++实现PCA

#include<bits/stdc++.h>
using namespace std;// 读取鸢尾花数据集到一个二维数组中
vector<vector<long double>> readIrisData(const string& filename);// 读取第五列的值到一个向量中
vector<long double> readfifthValue(const string& filename);// 从矩阵 A 非对角元中选择最大的元素,并返回其位置
pair<int, int> chooseMax(vector<vector<long double>> A);// 计算矩阵 A 的转置
vector<vector<long double>> calAT(vector<vector<long double>> A);// 计算矩阵 A 和其转置的乘积
vector<vector<long double>> calAAT(vector<vector<long double>> A);// 计算矩阵Q^T * A * Q的每个元素,使用给定的参数 p, q, t, c, d
long double calculateElement(const vector<vector<long double>> A, int i, int j, long double p, long double q, long double t, long double c, long double d);// 计算矩阵 Q^T * A * Q
vector<vector<long double>> calQTAQ(vector<vector<long double>> A);// 判断Jacobi迭代方法是否满足结束条件
int judgeEnd(vector<vector<long double>> A);// 计算矩阵 A 的特征值
vector<long double> calEigenValue(vector<vector<long double>> A);// 对矩阵 A 进行列主元化成上三角
vector<vector<long double>> Column_Elimination(vector<vector<long double>> A);// 求解系数矩阵为上三角矩阵A的线性方程组
vector<long double> SolveUpperTriangle(vector<vector<long double>> A, vector<long double> b);// 解系数矩阵为上三角矩阵 A 的线性方程组,且A全为0的行数为 cnt
vector<vector<long double>> solve(vector<vector<long double>> A, int cnt);// 计算矩阵 A 的特征向量,使用给定的特征值
vector<vector<long double>> calEigenVector(vector<vector<long double>> A, vector<long double> eigenValue);// 计算 Sigma 矩阵,使用给定的特征值 x 和矩阵的行数 n1 和列数 n2
vector<vector<long double>> calSigma(vector<long double> x,int n1, int n2);// 计算向量 x 的欧几里得范数
long double EuclideanNorm(vector<long double> x);// 对矩阵 A 进行归一化
vector<vector<long double>> Normalization(vector<vector<long double>> A);// 计算矩阵 A 和 B 的乘积
vector<vector<long double>> multiplyMatrices(const vector<vector<long double>> A, const vector<vector<long double>> B);int main()
{vector<vector<long double>> X = calAT(readIrisData("iris.txt"));int n1 = X.size();int n2 = X[0].size();long double sum = 0;for(int i = 0; i < n1; i++){long double sum = 0;for(int j = 0; j < n2; j++)sum += X[i][j];long double avg = sum / n2;for(int j = 0; j < n2; j++)X[i][j] -= avg;}cout << "X: " << endl;for(int i = 0; i < n1; i++){for(int j = 0; j < n2; j++)cout << X[i][j] << " ";cout << endl;}vector<vector<long double>> XT = calAT(X);vector<vector<long double>> XXT = multiplyMatrices(X, XT);vector<vector<long double>> Var(n1, vector<long double>(n1));for(int i = 0; i < n1; i++)for(int j = 0; j < n1; j++)Var[i][j] = XXT[i][j] / n2;vector<long double> x =calEigenValue(Var);sort(x.begin(), x.end());reverse(x.begin(), x.end());cout<<"特征值:"<<endl;for(int i = 0; i < n1; i++)cout << x[i] << " ";vector<long double> x1;x1.reserve(x.size());unique_copy(x.begin(), x.end(), back_inserter(x1));vector<vector<long double>> EigenVector = Normalization(calEigenVector(Var, x1));vector<vector<long double>> P(EigenVector.begin(), next(EigenVector.begin(), 2));cout << "P: " << endl;for(int i = 0; i < 2; i++){for(int j = 0; j < n1; j++)cout << P[i][j] << " ";cout << endl;}vector<vector<long double>> Y = multiplyMatrices(P, X);cout << "Y: " << endl;for(int i = 0; i < 2; i++){for(int j = 0; j < n2; j++)cout << Y[i][j] << " ";cout << endl;}return 0;
}// 读取鸢尾花数据集到一个二维数组中
vector<vector<long double>> readIrisData(const string& filename) {ifstream file(filename);vector<vector<long double>> X;string line;while (getline(file, line)) {stringstream ss(line);vector<long double> row;string value;int counter = 0;while (getline(ss, value, ',') && counter < 4) {row.push_back(stod(value));counter++;}X.push_back(row);}return X;
}// 读取第五列的值到一个向量中
vector<long double> readfifthValue(const string& filename) {ifstream file(filename);vector<long double> fifthValues;string line;while (getline(file, line)) {stringstream ss(line);string value;int counter = 0;while (getline(ss, value, ',') && counter < 4) {counter++;}if (counter == 4) { long double fifthValue = stold(value);fifthValues.push_back(fifthValue);}}return fifthValues;
}// 找到矩阵 A 中非对角元中绝对值最大的元素,并返回其位置
pair<int, int> chooseMax(vector<vector<long double>> A)
{long double max = 0;pair<int, int> maxPos;int n = A.size();for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)if(i != j && fabsl(A[i][j]) > max){max = fabsl(A[i][j]);maxPos = make_pair(i, j);}return maxPos;
}// 计算矩阵 A 的转置
vector<vector<long double>> calAT(vector<vector<long double>> A)
{int n1 = A.size();int n2 = A[0].size();vector<vector<long double>> AT(n2, vector<long double>(n1));for(int i = 0; i < n1; i++)for(int j = 0; j < n2; j++)AT[j][i] = A[i][j];return AT;
}// 计算两个矩阵的乘积
vector<vector<long double>> multiplyMatrices(const vector<vector<long double>> A, const vector<vector<long double>> B) {int n1 = A.size();int n2 = B[0].size();int n3 = A[0].size();vector<vector<long double>> result(n1, vector<long double>(n2, 0.0));for(int i = 0; i < n1; i++) {for(int j = 0; j < n2; j++) {for(int k = 0; k < n3; k++) {result[i][j] += A[i][k] * B[k][j];}}}return result;
}// 计算矩阵Q^T * A * Q的每个元素,使用给定的参数 p, q, t, c, d
long double calculateElement(const vector<vector<long double>> A, int i, int j, long double p, long double q, long double t, long double c, long double d) {if (i == p && j == p)return A[p][p] - t * A[p][q];else if (i == q && j == q)return A[q][q] + t * A[p][q];else if ((i == p && j == q) || (i == q && j == p))return 0;else if (i != q && i != p && (j == p || j == q))return (j == p ? c : d) * A[p][i] - (j == p ? d : (-c)) * A[q][i];else if ((i == p || i == q) && j != q && j != p)return (i == p ? c : d) * A[p][j] - (i == p ? d : (-c)) * A[q][j];elsereturn A[i][j];
}// 计算矩阵 Q^T * A * Q
vector<vector<long double>> calQTAQ(vector<vector<long double>> A)
{int n = A.size();pair<int, int> maxPos = chooseMax(A);int row = maxPos.first;int col = maxPos.second;long double s = (A[col][col] - A[row][row]) / (2 * A[row][col]);long double t = 0;if(s == 0)t = 1;else if(abs(-s + sqrt(1 + s * s)) <= abs(-s - sqrt(1 + s * s)))t = -s + sqrt(1 + s * s);elset = -s - sqrt(1 + s * s);long double c = 1 / sqrt(1 + t * t);long double d = t * c;vector<vector<long double>> QTAQ(n, vector<long double>(n));for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)QTAQ[i][j] = calculateElement(A, i, j, row, col, t, c, d);return QTAQ;
}// 判断Jacobi迭代方法是否满足结束条件
int judgeEnd(vector<vector<long double>> A)
{int i, j;int n = A.size();for(i = 0; i < n; i++)for(j = 0; j < n; j++)if(i != j && fabsl(A[i][j]) >= 1e-6)return 0;if(i == n && j == n) return 1;
}// 计算矩阵 A 的特征值
vector<long double> calEigenValue(vector<vector<long double>> A)
{int n = A.size();vector<long double> eigenValue(n);vector<vector<long double>> QTAQ= calQTAQ(A);int i, j;while(!judgeEnd(QTAQ))QTAQ = calQTAQ(QTAQ);for(i = 0; i < n; i++)eigenValue[i] =QTAQ[i][i];return eigenValue;
}// 对矩阵 A 进行列主元化成上三角
vector<vector<long double>> Column_Elimination(vector<vector<long double>> A)
{int n = A.size();vector<vector<long double>> Temp(n, vector<long double>(n));for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)Temp[i][j] = A[i][j];for(int col = 0; col < n; col++){long double maxnum = abs(Temp[col][col]);int maxrow = col;for(int row = col + 1; row < n; row++){if(abs(Temp[row][col]) > maxnum){maxnum = abs(Temp[row][col]);maxrow = row;}}swap(Temp[col], Temp[maxrow]);for(int row = col + 1; row < n; row++){long double res = Temp[row][col] / Temp[col][col];for(int loc = col; loc < n; loc++)Temp[row][loc] -= Temp[col][loc] * res; }}return Temp;
}// 求解系数矩阵为上三角矩阵A的线性方程组
vector<long double> SolveUpperTriangle(vector<vector<long double>> A, vector<long double> b)
{int n = A.size();vector<long double> x(n);vector<vector<long double>> Temp(n, vector<long double>(n+1));for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)Temp[i][j] = A[i][j];for(int i = 0; i < n; i++)Temp[i][n] = b[i];for(int row = n-1; row >= 0; row--){for(int col = row + 1; col < n; col++){Temp[row][n] -= Temp[col][n] * Temp[row][col] / Temp[col][col];Temp[row][col] = 0;}Temp[row][n] /= Temp[row][row];Temp[row][row] = 1;}for(int i = 0; i < n; i++)x[i] = Temp[i][n];return x;
}// 解系数矩阵为上三角矩阵 A 的线性方程组,且A全为0的行数为 cnt
vector<vector<long double>> solve(vector<vector<long double>> A, int cnt)
{int n = A.size();vector<vector<long double>> x(cnt, vector<long double>(n));vector<vector<long double>> Temp(n-cnt, vector<long double>(n-cnt));vector<long double> Tempb(n-cnt);for(int i = 0; i < cnt; i++){for(int j = n - 1; j >= n - cnt; j--){if(j >= n - i)x[i][j] = 0;elsex[i][j] = 1;}}for(int i = 0; i < n - cnt; i++)for(int j = 0; j < n - cnt; j++)Temp[i][j] = A[i][j];for(int i = 0; i < cnt; i++){for(int j = n - cnt - 1; j >=  0; j--){Tempb[j] = 0;for(int k = 0; k < cnt; k++)Tempb[j] -= A[j][n- cnt + k] * x[i][n- cnt + k];}vector<long double> res = SolveUpperTriangle(Temp, Tempb);for(int j = 0; j < n - cnt; j++)x[i][j] = res[j];}return x;
}// 使用给定的特征值计算矩阵 A 的特征向量
vector<vector<long double>> calEigenVector(vector<vector<long double>> A, vector<long double> eigenValue)
{int n = A.size();int num = 0;vector<vector<long double>> x(n, vector<long double>(n));vector<vector<long double>> tempMartix(n, vector<long double>(n));vector<vector<long double>> eigenVector(n, vector<long double>(n));for(int k = 0; k < n; k++){for(int i = 0; i < n; i++)for(int j = 0; j < n; j++)i == j ? tempMartix[i][j] = A[i][j] - eigenValue[k] : tempMartix[i][j] = A[i][j];vector<vector<long double>> B = Column_Elimination(tempMartix);int cnt = 0;//记录消元后全为0的行数for(int i = 0; i < n; i++){for(int j = 0; j < n; j++){if(fabsl(B[i][j]) > 1e-7)break;else if(j == n - 1)cnt++;}}vector<vector<long double>> result = solve(B, cnt);for(int i = 0; i < cnt; i++)copy(result[i].begin(), result[i].end(), x[num + i].begin());num += cnt;}return x;
}// 使用给定的特征值 x 和矩阵的行数 n1 和列数 n2,计算 Sigma 矩阵
vector<vector<long double>> calSigma(vector<long double> x, int n1, int n2)
{vector<vector<long double>> Sigma(n1, vector<long double>(n2));for(int i = 0; i < min(n1, n2); i++)Sigma[i][i] = sqrt(x[i]);return Sigma;
}// 计算向量 x 的欧几里得范数
long double EuclideanNorm(vector<long double> x)
{long double norm = 0;for(int i = 0; i < x.size(); i++)norm += x[i] * x[i];return sqrt(norm);
}// 对矩阵 A 进行归一化
vector<vector<long double>> Normalization(vector<vector<long double>> A)
{int rows = A.size();for(int i = 0; i < rows; i++){long double norm = EuclideanNorm(A[i]);int cols = A[i].size();for(int j = 0; j < cols; j++)A[i][j] /= norm;}return A;
}

python实现PCA并将结果可视化

import numpy as np
from scipy.linalg import eigh
import matplotlib.pyplot as pltdef readIrisData(filename):data = np.genfromtxt(filename, delimiter=',', dtype='float', encoding=None)return data[:, :4].T, data[:, 4]X, labels = readIrisData("iris.txt")Var = np.cov(X)
x, EigenVector = eigh(Var)
x = sorted(x, reverse=True)P = EigenVector[:, -2:].T
Y = np.dot(P, X)plt.figure()
label_set = set(labels)
colors = ['r', 'g', 'b']
shapes = ['o', 's', '^']for i, label in enumerate(label_set):#enumerate函数返回每个标签及其索引x = [Y[0, j] for j in range(Y.shape[1]) if labels[j] == label]y = [Y[1, j] for j in range(Y.shape[1]) if labels[j] == label]plt.scatter(x, y, color=colors[i], marker=shapes[i], label=label)plt.legend()#添加图例
plt.show()

可视化结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/620426.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Social to Sales,洞见生意进阶生机丨数说故事重磅发布2024全新战略

洞察&#xff0c;让生意发生。 4月12日&#xff0c;以“Social to Sales 洞察让生意发生”为主题的2024数说故事D3智能营销论坛于上海圆满举办&#xff0c;数说故事与来自清华大学、中欧国际工商学院、周大福、小红书、澎湃新闻、互联网大厂营销专家等12位重磅级嘉宾&#xf…

实验一:配置IP地址

实验环境 主机A和主机B通过一根网线相连 需求描述 为两台主机配置IP地址&#xff0c;验证IP地址是否生效&#xff0c;验证同一网段的两台主机可以互通&#xff0c;不同网段的主机不能直接互通 一.实验拓扑 二.推荐步骤 1.为两台主机配置P地址&#xff0c;主机A为192.168.1.…

✌粤嵌—2024/3/13—反转字符串中的单词

代码实现&#xff1a; // 反转单词 左闭右闭 void reverse(char *str, int l, int r) {while (l < r) {char temp str[l];str[l] str[r];str[r] temp;l;r--;} }char* reverseWords(char *s) {int n strlen(s);char *ret malloc(sizeof(char) * (n 1));int retSize 0;…

java实现简单图书管理系统(附带源码)

项目要求 该项目会用到类和对象&#xff0c;封装、继承、多态、接口、等&#xff0c;会帮你巩固并加强这类知识 设计要求及思路 1.要求有两套系统分别给管理员和普通用户使用&#xff0c;经过开始的选择会有两个对应功能不同的菜单&#xff0c;这里两种角色我们可以放一个包…

活动预告|NineData 创始人CEO叶正盛将参加QCon全球软件开发大会,共话AI大模型技术在数据库DevOps的实践

4月13日下午&#xff0c;NineData创始人&CEO叶正盛即将参加InfoQ中国主办的『QCon全球软件开发大会北京站』的技术大会。在本次技术峰会上&#xff0c;叶正盛将以《AI大模型技术在数据库DevOps的实践》为主题&#xff0c;深入剖析AI大模型技术在数据库DevOps领域的最新进展…

跨境电商SaaS独立站的真面目...

跨境电商独立站自外贸交易开始&#xff0c;就一直存在&#xff0c;接触过电商的朋友应该都听过&#xff0c;但大部分人仅仅只是停留在听过的阶段&#xff0c;并没有真正的去了解它&#xff1b;独立站&#xff0c;顾名思义就是一个独立的网站&#xff0c;不依附任何平台&#xf…

swagger文档无法访问

1. 报错异常 Unable to render this definition The provided definition does not specify a valid version field. Please indicate a valid Swagger or OpenAPI version field. Supported version fields are swagger: "2.0" and those that match openapi: 3.0…

git 拉取代码仓库代码报错(合并错误 refusing to merge unrelated histories)

文章目录 问题描述解决方案第一步第二步 问题描述 今天同事新建了一个代码仓库&#xff0c;仓库和我现在的仓库不是一个&#xff0c;我需要切换到新的仓库下&#xff0c;但是现在新仓库的代码我现在本地的代码不一致&#xff0c;导致我在拉取新仓库代码是报错 合并错误 refusin…

Python数学建模学习-PageRank算法

1-基本概念 PageRank算法是由Google创始人Larry Page在斯坦福大学时提出&#xff0c;又称PR&#xff0c;佩奇排名。主要针对网页进行排名&#xff0c;计算网站的重要性&#xff0c;优化搜索引擎的搜索结果。PR值是表示其重要性的因子。 中心思想&#xff1a; 数量假设&#…

如何在CentOS本地部署FastDFS文件系统并实现无公网IP远程上传下载内网文件

文章目录 前言1. 本地搭建FastDFS文件系统1.1 环境安装1.2 安装libfastcommon1.3 安装FastDFS1.4 配置Tracker1.5 配置Storage1.6 测试上传下载1.7 与Nginx整合1.8 安装Nginx1.9 配置Nginx 2. 局域网测试访问FastDFS3. 安装cpolar内网穿透4. 配置公网访问地址5. 固定公网地址5.…

英语技术会议常用语

个人整理。 自我介绍&#xff1a; Hello everyone, Im [Your Name], and Im excited to be here today. I work as [Your Position] at [Your Company/Organization], where I focus on [Brief Description of Your Role or Expertise]. Im looking forward to our discussion…

demo(四)nacosgateway(2)gatewayspringsercurity

一、思路 1、整体思路 用户通过客户端访问项目时&#xff0c;前端项目会部署在nginx上&#xff0c;加载静态文件时直接从nginx上返回即可。当用户在客户端操作时&#xff0c;需要调用后端的一些服务接口。这些接口会通过Gateway网关&#xff0c;网关进行一定的处理&#xff0…