1+ #coding=utf-8
2+ #Author:Harold
3+ #Date:2021-1-27
4+ #Email:zenghr_zero@163.com
5+
6+ '''
7+ 数据集:cars
8+ 数据集数量:387
9+ -----------------------------
10+ 运行结果:
11+ 主成分个数:3
12+ 可解释偏差:0.71
13+ 运行时长:0.14s
14+ '''
15+
16+ import numpy as np
17+ import pandas as pd
18+ import time
19+
20+
21+ #定义加载数据的函数
22+ def load_data (file ):
23+ '''
24+ INPUT:
25+ file - (str) 数据文件的路径
26+
27+ OUTPUT:
28+ df - (dataframe) 读取的数据表格
29+ X - (array) 特征数据数组
30+
31+ '''
32+ df = pd .read_csv (file ) #读取csv文件
33+ df .drop ('Sports' , axis = 1 , inplace = True ) #去掉类别数据
34+ X = np .asarray (df .values ).T #将数据转换成数组
35+ return df , X
36+
37+
38+ #定义规范化函数,对每一列特征进行规范化处理,使其成为期望为0方差为1的标准分布
39+ def Normalize (X ):
40+ '''
41+ INPUT:
42+ X - (array) 特征数据数组
43+
44+ OUTPUT:
45+ X - (array) 规范化处理后的特征数据数组
46+
47+ '''
48+ m , n = X .shape
49+ for i in range (m ):
50+ E_xi = np .mean (X [i ]) #第i列特征的期望
51+ Var_xi = np .var (X [i ], ddof = 1 ) #第i列特征的方差
52+ for j in range (n ):
53+ X [i ][j ] = (X [i ][j ] - E_xi ) / np .sqrt (Var_xi ) #对第i列特征的第j条数据进行规范化处理
54+ return X
55+
56+
57+ #定义奇异值分解函数,计算V矩阵和特征值
58+ def cal_V (X ):
59+ '''
60+ INPUT:
61+ X - (array) 特征数据数组
62+
63+ OUTPUT:
64+ eigvalues - (list) 特征值列表,其中特征值按从大到小排列
65+ V - (array) V矩阵
66+
67+ '''
68+ newX = X .T / np .sqrt (X .shape [1 ]- 1 ) #构造新矩阵X'
69+ Sx = np .matmul (newX .T , newX ) #计算X的协方差矩阵Sx = X'.T * X'
70+ V_T = [] #用于保存V的转置
71+ w , v = np .linalg .eig (Sx ) #计算Sx的特征值和对应的特征向量,即为X’的奇异值和奇异向量
72+ tmp = {} #定义一个字典用于保存特征值和特征向量,字典的键为特征值,值为对应的特征向量
73+ for i in range (len (w )):
74+ tmp [w [i ]] = v [i ]
75+ eigvalues = sorted (tmp , reverse = True ) #将特征值逆序排列后保存到eigvalues列表中
76+ for i in eigvalues :
77+ d = 0
78+ for j in range (len (tmp [i ])):
79+ d += tmp [i ][j ] ** 2
80+ V_T .append (tmp [i ] / np .sqrt (d )) #计算特征值i的单位特征向量,即为V矩阵的列向量,将其保存到V_T中
81+ V = np .array (V_T ).T #对V_T进行转置得到V矩阵
82+ return eigvalues , V
83+
84+
85+ #定义主成分分析函数
86+ def do_pca (X , k ):
87+ '''
88+ INPUT:
89+ X - (array) 特征数据数组
90+ k - (int) 设定的主成分个数
91+
92+ OUTPUT:
93+ fac_load - (array) 因子负荷量数组
94+ dimrates - (list) 可解释偏差列表
95+ Y - (array) 主成分矩阵
96+
97+ '''
98+ eigvalues , V = cal_V (X ) #计算特征值和V矩阵
99+ Vk = V [:, :k ] #取V矩阵的前k列
100+ Y = np .matmul (Vk .T , X ) #计算主成分矩阵,将m*n的样本矩阵X转换成k*n的样本主成分矩阵
101+ dimrates = [i / sum (eigvalues ) for i in eigvalues [:k ]] #计算可解释偏差,即前k个奇异值中每个奇异值占奇异值总和的比例,这个比例表示主成分i可解释原始数据中的可变性的比例
102+ fac_load = np .zeros ((k , X .shape [0 ])) #用来保存主成分的因子负荷量
103+ for i in range (k ):
104+ for j in range (X .shape [0 ]):
105+ fac_load [i ][j ] = np .sqrt (eigvalues [i ]) * Vk [j ][i ] / np .sqrt (np .var (X [j ])) #计算主成分i对应原始特征j的因子负荷量,保存到fac_load中
106+ return fac_load , dimrates , Y
107+
108+
109+ if __name__ == "__main__" :
110+ df , X = load_data ('cars.csv' ) #加载数据
111+ start = time .time () #保存开始时间
112+ X = Normalize (X ) #对样本数据进行规范化处理
113+ k = 3 #设定主成分个数为3
114+ fac_load , dimrates , Y = do_pca (X , k ) #进行主成分分析
115+ pca_result = pd .DataFrame (fac_load , index = ['Dimension1' , 'Dimension2' , 'Dimension3' ], columns = df .columns ) #将结果保存为dataframe格式
116+ pca_result ['Explained Variance' ] = dimrates #将可解释偏差保存到pca_result的'Explained Variance'列
117+ end = time .time () #保存结束时间
118+ print ('Time:' , end - start )
0 commit comments