目录
引言
在处理高维数据时,我们经常会遇到 "维度灾难"—— 随着特征数量增加,数据稀疏性上升,模型训练难度增大,甚至可能出现过拟合。主成分分析(PCA)作为一种经典的降维方法,能够在保留数据核心信息的前提下,有效降低特征维度,是数据预处理中的重要工具。本文将从原理到实战,全面解析 PCA 降维技术。
一、PCA 的核心思想
PCA 的本质是通过线性变换将高维数据映射到低维空间,同时尽可能保留数据中的 "重要信息"。这里的 "重要信息" 用方差来衡量 —— 方差越大,说明数据在该方向上的分布越分散,包含的信息量越多。
举个直观的例子:假设我们有一批二维数据点,这些点大致分布在一条直线附近。此时我们可以用每个点在这条直线上的投影值来表示该点(将二维降为一维),因为投影值已经包含了原始数据的大部分信息。这条直线就是我们要找的 "第一主成分"。
PCA 的目标就是找到这样一组相互正交的主成分,使得数据在这些主成分上的投影方差最大化。通常我们只保留前 k 个主成分,即可实现将 n 维数据降为 k 维(k < n)。
二、PCA 的数学原理
PCA 的实现过程可以概括为以下步骤:
- 数据标准化:对原始数据进行均值归一化(使各特征均值为 0)和方差缩放(使各特征方差为 1),因为 PCA 对数据的尺度敏感。
- 计算协方差矩阵:协方差矩阵描述了特征之间的相关性,对于 n 维数据,协方差矩阵是一个 n×n 的对称矩阵。
- 特征值分解:对协方差矩阵进行特征值分解,得到特征值和对应的特征向量。特征值表示对应主成分的方差大小,特征向量则是主成分的方向。
- 选择主成分:将特征值从大到小排序,选择前 k 个最大的特征值对应的特征向量,组成投影矩阵。
- 数据投影:将标准化后的原始数据与投影矩阵相乘,得到降维后的 k 维数据。
注:在实际实现中,当数据维度很高时,通常会采用 SVD(奇异值分解)代替特征值分解,因为 SVD 在计算效率上更有优势。
三、为什么要进行主成分分析
1.数据可视化
主成分分析可以将高维数据映射到二维或三维空间中,在可视化分析中提供更好的观察和理解数据的能力。通过将数据投影到较低维度的空间,我们可以更容易地检测数据的分布、聚类和异常值。
2.数据压缩
主成分分析可以通过保留较高方差的主成分,将数据从高维度降低到低维度。这有助于减少存储空间和计算成本,并提高数据处理效率。
3.特征选择
主成分分析可以帮助识别出在数据中具有最大方差的特征。通过选择具有较高方差的主成分,我们可以从原始数据中提取出最重要的特征。
4.数据预处理
主成分分析可以用于数据预处理的步骤。通过将数据投影到较低维度的空间中,我们可以减少噪声和冗余数据,从而改善后续的数据分析和建模结果。
四、PCA中的数学
1、基
什么是基?基,也称基底,是描述、刻画向量空间的基本工具。图像表示:
如图所示,横纵坐标轴叫做基底,单位向量(0,1)和(1,0)叫做这个二维空间的一组基,而向量A的坐标完全由这组基来表示,如下所示:
注意:这里的x和y和之前的表示不同,之前的是前面多少列为特征集,有一列作为标签列,而现在的则是将原本的数据做了一个转置,得到现在的,前多少行为特征集,有一列作为标签行。即,一列表示一条数据。
所以这里表示的是这一组基乘以x方向的长度与y方向上的长度,最终得到的值就是这个向量在当前的基底表示的坐标为(3,2)
什么样的向量可以成为基?
任何两个线性无关的二维向量都可以成为一组基,即表示两组向量互相垂直就是线性无关,如下图所示,蓝色线表示一组新的基底,原本的向量映射在不同基底上对应的坐标不同。
什么样的向量可以成为基?
任何两个线性无关的二维向量都可以成为一组基,即表示两组向量互相垂直就是线性无关,如下图所示,蓝色线表示一组新的基底,原本的向量映射在不同基底上对应的坐标不同。
2、基变换
基变换的本质: 在保持向量空间结构(线性运算、内积等)不变的前提下,通过可逆矩阵实现同一向量 / 线性变换在不同基下的坐标表示转换。基变换不改变向量的 “本质”(如长度、夹角),仅改变其坐标表示。
如图所示,将原本的(x1,x2)基底变换为(y1,y2),此时新的坐标系单位向量坐标则不能表示为(1,1),而应该表示为( ,
)
此时新的基底的一组基则表示为( ,
),(
,
),如下图所示
此时坐标虽然变了,但是模没变,长度还是原来的长度,但是表达方式改变了
将(3,2)映射到新的基上,由于新的基的模是1,所以直接相乘就能得到(3,2)在新的的坐标系(紫色坐标系)下的坐标,如下:
多个二维向量变换
其计算方式和上述类似,同样是将新的基底的一组基乘以多个二维向量,得到的新的坐标:
此时三组向量(1,1),(2,2),(3,3),他们在新的坐标系中表示的坐标为上图所示的状态
多个坐标转换到新的坐标系
上图表示的是n维的向量向R维空间映射,作内积得到的结果为R行m列,因为基的第一行乘以特征第一列得到一个结果,第一行乘以第二列得到第二个几个,然后一行乘以所有的列,得到结果的一行,而基有R行,乘以m列后,得到的结果就为R行m列,即将原本的维度为n的数据,转变成了维度为R的数据,这就是卷积,即一个矩阵和另一个矩阵相乘,将一个矩阵变换到新的空间中。
五、最优基的选择
1、如何才能保留较多的原始数据信息?
如下所示有一堆数据点,将他们映射到新的空间后投影到坐标轴上得到的状态:
此时可以发现,投影到不同的轴上的数据点紧密程度不同,从而得到投影的轴上的点的分布状态,而数据的离散程度可以用方差来表示,方差越大则表示数据的离散程度越大,如果我们取方差小的当做新的数据,此时点之间的排布非常紧密,很多个点重合在一起,此时则无法满足较多的保存原始数据,所以我们更需要离散程度更高的当做新的数据。
2、方差公式
3、多维数据降维
对于多次降维,以 三维数据来说,将数据降到二维,寻找的基为 方差最大 的方向,再次将数据降到一维, 必然与降到二维的基无限接近。依次寻找方差次大的基,如果两个基基本重合, 这样的一个基是没有用的,我们应该让两个基 线性无关 。【线性无关才能保留更多的原始信息】
4、协方差
1、含义
协方差表示两个字段之间的相关性,当协方差为0时,表示两个字段完全独立。公式如下:
2、目标
利用协方差为0,选择另一组基,这组基的方向一定与第一组基正交。
3、协方差矩阵
假设我们有a,b两个字段,组成矩阵:X,用X乘以其转置,并乘以1/m:
此时得到的即为协方差矩阵,可以发现,其对角线上的数据为方差,斜对角线上的数据为协方差,此时如果协方差的值为0,则表示两个字段完全独立。
5、协方差矩阵对角化
(1)含义
原始数据:X —>协方差矩阵:C
一组基按行组成的矩阵:P
基变换后的数据:Y—>协方差矩阵:D
隐含信息:Y = PX
(2)优化目标
寻找一个矩阵P,满足PC P的转置是一个对角矩阵,并且对角元素按从大到小依次排列,那么P的前K行就是要寻找的基,用P的前K行组成的矩阵乘以X就使得X从N维降到了K维并满足上述优化条件。
协方差矩阵C对角化:
实对称矩阵: 矩阵转置等于其本身均为0
对角化: 除主对角线之外其余元素
6、求解步骤
1)将原始数据按列组成n行m列矩阵X;
2)将X的每一行(代表一个属性字段)进行零均值化,即减去这一行的均值
3)求出协方差矩阵:
4)求出协方差矩阵的特征值及对应的特征向量;
5)将特征向量按对应特征值大小从上到下按行排列成矩阵,取前k行组成矩阵P
6)Y=PX即为降维到k维后的数据。
六、参数解析
PCA(n_components=None, copy=True, whiten=False, svd_solver=’auto’, tol=0.0, iterated_power=’auto’, random_state=None)[source]
1.参数
1)n_components:指定希望PCA降维后的特征维度数目
指定整数,表示要降维到的目标,比如十维的数据,指定n_components=5,表示将十维数据降维到五维,如果为小数,表示累计方差百分比。
2)copy :bool类型,默认为True。
表示是否在运行算法时,将原始训练数据复制一份。若为True,则运行PCA算法后,原始训练数据的值不会有任何改变,因为是在原始数据的副本上进行运算;若为False,则运行PCA算法后,原始训练数据的值会改,因为是在原始数据上进行降维计算
3)whiten:判断是否进行白化。
白化就是对降维后的数据的每个特征进行归一化,让方差都为1.默认值是False,即不进行白化。
4)svd_solver:即指定奇异值分解SVD的方法
由于特征分解是奇异值分解SVD的一个特例,一般的PCA库都是基于SVD实现的。有4个可以选择的值:{‘auto’, ‘full’, ‘arpack’, ‘randomized’}。randomized一般适用于数据量大,数据维度多同时主成分数目比例又较低的PCA降维,它使用了一些加快SVD的随机算法。 full则是传统意义上的SVD,使用了scipy库对应的实现。arpack和randomized的适用场景类似,区别是randomized使用的是scikit-learn自己的SVD实现,而arpack直接使用了scipy库的sparse SVD实现。默认是auto,即PCA类会自己去在前面讲到的三种算法里面去权衡,选择一个合适的SVD算法来降维。
2、属性
components_:array, shape (n_components, n_features) 指表示主成分系数矩阵
explained_variance_:降维后的各主成分的方差值。方差值越大,则说明越是重要的主成分。
explained_variance_ratio_:降维后的各主成分的方差值占总方差值的比例,这个比例越大,则越是重要的主成分。【一般看比例即可 >90%】
七、代码调用
1. 导入必要的库
import pandas as pd # 数据处理库,用于读取和操作CSV数据
from sklearn.decomposition import PCA # 主成分分析,用于降维
from sklearn.preprocessing import StandardScaler # 数据标准化工具
from sklearn.linear_model import LogisticRegression # 逻辑回归模型
from sklearn.model_selection import train_test_split # 划分训练集和测试集
from sklearn.metrics import classification_report # 生成分类评估报告
2. 读取数据并提取特征与标签
数据集如下:
file = pd.read_csv('creditcard.csv') # 读取信用卡欺诈数据集
x = file.iloc[:, :-1] # 提取特征(除最后一列外的所有列)
y = file.iloc[:, -1] # 提取标签(最后一列,通常表示是否为欺诈交易:0=正常,1=欺诈)
数据集creditcard.csv
是经典的信用卡欺诈检测数据,包含时间、交易金额等特征,标签列Class
标记交易是否为欺诈。
3. 数据标准化
scaler = StandardScaler() # 初始化标准化器
x_scaled = scaler.fit_transform(x) # 对特征进行标准化(均值为0,方差为1)
- 为什么标准化?
PCA 和逻辑回归对特征的尺度敏感(例如 “交易金额” 可能远大于其他特征),标准化能让所有特征在同一尺度上,避免某一特征对结果产生过度影响。
4. 使用 PCA 进行降维
model = PCA(n_components=20) # 初始化PCA模型,指定降维到20个主成分
x_reduced = model.fit_transform(x_scaled) # 对标准化后的特征进行降维
- PCA 作用:将高维特征(原始数据可能有 30 + 特征)压缩到 20 个主成分,减少数据维度,同时保留大部分关键信息。
- 降维的好处:减少计算量、避免过拟合、简化模型。
5. 划分数据集并训练降维后的逻辑回归模型
# 划分降维后的数据为训练集(80%)和测试集(20%),固定随机种子保证结果可复现
x_train, x_test, y_train, y_test = train_test_split(x_reduced, y, test_size=0.2, random_state=5)
# 初始化逻辑回归模型:max_iter=1000(确保收敛),class_weight='balanced'(处理类别不平衡)
lr = LogisticRegression(max_iter=1000, class_weight='balanced')
lr.fit(x_train, y_train) # 用降维后的训练集训练模型
y_pred = lr.predict(x_test) # 用训练好的模型预测测试集
print("降维分类报告:")
print(classification_report(y_test, y_pred)) # 输出降维后模型的评估报告
- class_weight='balanced':信用卡数据中欺诈样本(1)通常远少于正常样本(0),此参数会自动调整权重,让模型更关注少数类(欺诈样本)。
- 分类报告:包含精确率、召回率、F1 分数等指标,评估模型对两类样本的识别能力。
6. 用原始数据训练逻辑回归模型(对比实验)
# 划分原始特征数据为训练集和测试集(保持与上面相同的随机种子,确保对比公平)
x_train1, x_test1, y_train1, y_test1 = train_test_split(x, y, test_size=0.2, random_state=5)
# 用原始数据训练新的逻辑回归模型(参数与上面一致)
lr = LogisticRegression(max_iter=1000, class_weight='balanced')
lr.fit(x_train1, y_train1)
y_pred1 = lr.predict(x_test1) # 预测原始数据的测试集
print("不降温分类报告:")
print(classification_report(y_test1, y_pred1)) # 输出原始数据模型的评估报告
- 这部分是对照组:不做降维,直接用原始特征训练模型,用于和降维后的模型对比。
- 保持
random_state=5
确保两个实验的训练集 / 测试集划分完全一致,保证对比的公平性。
核心目的与结论
通过对比两个分类报告,可以观察:
- 降维后模型的性能(如欺诈样本的召回率)是否与原始模型接近;
- 降维是否在损失少量信息的情况下,简化了模型(减少特征数量);
- 对于信用卡欺诈检测这类场景,重点关注少数类(欺诈样本)的召回率是否达标。
通常情况下,PCA 降维后的模型性能会略低于原始模型,但计算速度更快,且如果降维保留了 90% 以上的信息,性能损失会很小。
完整代码及运行结果如下:
import pandas as pd
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
file = pd.read_csv('creditcard.csv')
x = file.iloc[:, :-1]
y = file.iloc[:, -1]
scaler = StandardScaler()
x_scaled = scaler.fit_transform(x)
model = PCA(n_components=20)
x_reduced = model.fit_transform(x_scaled)
x_train, x_test, y_train, y_test = train_test_split(x_reduced, y, test_size=0.2, random_state=5)
lr=LogisticRegression(max_iter=1000,class_weight='balanced')
lr.fit(x_train,y_train)
y_pred = lr.predict(x_test)
print("降维分类报告:")
print(classification_report(y_test, y_pred))
x_train1,x_test1,y_train1,y_test1=train_test_split(x,y,test_size=0.2,random_state=5)
lr=LogisticRegression(max_iter=1000,class_weight='balanced')
lr.fit(x_train1,y_train1)
y_pred1=lr.predict(x_test1)
print("不降温分类报告:")
print(classification_report(y_test1,y_pred1))