主成分分析(PCA)是一种常用的数据降维技术,特别适用于线性数据集。它是一种非参数化且简单的方法,却能产生强大的结果。本文将探讨PCA的数学基础,并提供从零开始的Python实现。
在深入讨论PCA之前,需要先了解以下几个概念:
协方差(Covariance):协方差用于描述两个变量之间的关系。如果协方差为正,则两个变量倾向于朝相同方向变化;如果协方差为负,则两个变量倾向于朝相反方向变化;如果协方差为0,则表明两个属性之间不存在关系。
方差(Variance):方差表示数据的离散程度,即数据值与均值的距离。
PCA的基本步骤可以总结如下,将详细探讨这些步骤:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
data = np.array([[1000 ,500],[2000, 800],[3000 ,1100],[4000 ,1500],[5000 ,1800],[8000,1900]])
df = pd.DataFrame(data,columns = ['Salary','Expense'])
接下来,将使用散点图来检查数据的分布并可视化相关性。
import seaborn as sns
plot = sns.lmplot(x='Salary', y='Expense', data=df, ci=None)
plt.title("Salary vs Expense")
由于数据中有两个属性,即工资和支出,因此协方差矩阵的形状将是2×2。请注意下面的协方差和方差的公式。如果x和y相同,则它将为同一属性产生方差。因此,在上述协方差矩阵中,对角线元素将产生工资和支出的方差。此外,协方差的一个属性是它是对称的,即协方差(x,y) = 协方差(y,x),这告诉协方差(工资,支出) = 协方差(支出,工资)。
这些术语听起来相当复杂,但并不难理解。这些术语在PCA中扮演着最重要的角色。
特征向量(Eigenvector):特征向量是一个非零向量,当受到线性变换时,只改变大小而不改变方向。这意味着如果将一个非零向量与上述协方差矩阵相乘,结果将是初始向量的缩放版本,而该缩放值就是特征值。
数学上,当一个特征向量与一个向量相乘时,将给出特征向量和一个标量值的乘积。
A * v = lambda * v
其中A是任何矩阵,v是特征向量,lambda是特征值。
import warnings
warnings.filterwarnings('ignore')
from sklearn.preprocessing import StandardScaler
ss = StandardScaler()
scaled = ss.fit_transform(data)
scaled
现在已经得到了标准化后的数据,接下来将计算协方差矩阵并计算特征值和特征向量。
from numpy import linalg
cov = np.cov(scaled[:,0], scaled[:,1])
val, vec = linalg.eig(cov)
print("Below we have eigenvectors from the covariance matrix")
print(vec)
print("Eigen Values for corresponding eigenvector")
print(val)
现在有了特征值和对应的特征向量。特征向量矩阵的不同列表示不同的特征向量。将选择与最高特征值对应的特征向量,这是第一个主成分。
var_exp_1 = print('Total variance explained by first principal component is',round(val[0]/val.sum(),2))
var_exp_2 = print('Total variance explained by second principal component is',round(val[1]/val.sum(),2))
当选择了一定数量的特征向量(具有较大特征值)并形成一个由这些向量组成的矩阵时,这个矩阵被称为特征向量。
需要注意的重要一点是,主成分是不相关的,因为它们是正交的,即它们是相互垂直的。
final_data = np.dot(scaled, np.array(vec.T[0]))
print(final_data)
from sklearn.decomposition import PCA
pca = PCA(n_components=1)
pca.fit(scaled)
print("Variance explained by principal component is", pca.explained_variance_ratio_)
print("Final output after PCA", pca.transform(scaled)[:,0])