主成分分析(Principal Component Analysis, PCA)是一种统计技术,主要用于简化数据集。通过将原始数据投影到较低维的空间,PCA帮助我们发现数据中的主要趋势和结构。本文将介绍PCA的基本概念、应用及其在数据科学中的重要性。
一、PCA的基本概念
PCA的核心思想是通过线性变换,将数据从高维空间转换到低维空间,同时尽可能保留数据的主要特征。具体来说,PCA通过以下几个步骤实现:
1. 数据中心化
在进行PCA之前,我们首先需要对数据进行中心化处理,即将每个特征的均值移至零。这是因为PCA依赖于协方差矩阵,而中心化数据可以确保协方差矩阵更好地反映数据的真实结构。
设原始数据矩阵为 (维度为 ,其中 是样本数, 是特征数),中心化后的数据矩阵 计算如下:
其中, 是数据矩阵 的均值向量。
2. 计算协方差矩阵
协方差矩阵用于衡量特征之间的相关性。协方差矩阵 的计算公式如下:
3. 计算特征值和特征向量
协方差矩阵的特征值和特征向量用于确定数据的主要方向和重要性。通过计算协方差矩阵的特征值和特征向量,我们可以找到数据在不同方向上的方差。
特征值(eigenvalue)表示主成分的重要性,而特征向量(eigenvector)表示主成分的方向。设协方差矩阵的特征值为 (从大到小排列),对应的特征向量为 。
4. 选择主成分
选择前 个最大的特征值对应的特征向量,构成新的低维空间。这里的 通常是通过累积解释方差(cumulative explained variance)来确定的。
累积解释方差定义为:
当累积解释方差达到某个阈值(例如95%)时,我们认为选取的主成分已经足够解释数据中的大部分信息。
5. 数据投影
将原始数据投影到选择的主成分方向上,得到降维后的数据。降维后的数据矩阵 ZZZ 计算如下:
其中, 是包含前 个特征向量的矩阵。
6. PCA的数学直观理解
PCA的目标是找到数据在新的坐标系下的最优表示,使得数据在该坐标系下的投影方差最大化。通过选择最大的特征值对应的特征向量,PCA能够最大限度地保留数据的主要变化趋势,从而实现降维和去噪的目的。
二、PCA实践
代码实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn .datasets import make_blobs
from sklearn.decomposition import PCA
def create_data(num_samples=100, num_features=2, centers=2, random_state=42):
X, y = make_blobs(n_samples=num_samples, n_features=num_features, centers=centers, random_state=random_state)
return X, y
def show_data(X, y):
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.show()
def visualize_svm(X, y, svm):
def get_hyperplane_value(x, w, b, offset):
return (-w[0] * x + b + offset) / w[1]
plt.scatter(X[:, 0], X[:, 1], marker='o', c=y)
ax = plt.gca()
xlim = ax.get_xlim()
ylim = ax.get_ylim()
x = np.linspace(xlim[0], xlim[1], 30)
y_pred = get_hyperplane_value(x, svm.w, svm.b, 0)
margin_plus = get_hyperplane_value(x, svm.w, svm.b, 1)
margin_minus = get_hyperplane_value(x, svm.w, svm.b, -1)
plt.plot(x, y_pred, 'k-')
plt.plot(x, margin_plus, 'k--')
plt.plot(x, margin_minus, 'k--')
plt.legend()
plt.show()
class SVM:
def __init__(self, lr=0.001, lambda_param=0.01, num_step=1000):
'''
:param lr: 学习率
:param lambda_param: 正则化参数
:param num_step: 步数
'''
self.lr = lr
self.lambda_param = lambda_param
self.num_step = num_step
self.w = None
self.b = None
def fit(self, X, y):
#初始化权重和偏置
num_samples, num_features = X.shape
self.w = np.zeros(num_features)
self.b = 0
#将标签从 0/1 转换为 -1/1。SVM 要求标签为 -1 和 1。
y_ = np.where(y <= 0, -1, 1)
#梯度下降
for _ in range(self.num_step):
for idx, x_i in enumerate(X):
#检查样本是否满足分类条件,更新权重和偏置
if y_[idx] * (np.dot(x_i, self.w) - self.b) >= 1:
self.w -= self.lr * (2 * self.lambda_param * self.w)
else:
self.w -= self.lr * (2 * self.lambda_param * self.w - np.dot(x_i, y_[idx]))
self.b -= self.lr * y_[idx]
def predict(self, X):
pred = np.dot(X, self.w) + self.b
return np.sign(pred)
X, y = create_data(num_features=10)
y = np.where(y==0, -1, 1)
print(X.shape)
pca = PCA(n_components=2)
X = pca.fit_transform(X)
show_data(X, y)
svm = SVM()
svm.fit(X, y)
visualize_svm(X, y, svm)
生成的数据集的特征维度为10,用PCA将数据集的特征维度降维为2。
生成的数据集形状:
PCA降维后:
之后用SVM(支持向量机)对数据集进行分类
运行结果
三、总结
PCA可以简化数据,减少维度,提高计算效率。在上面的实践中PCA把样本特征维度为10的数据集降维到2,大大简化了后面的SVM相关的计算。在保留主要信息的同时,减少数据冗余,让降维后的数据仍然能正确的分类。
但不足的是PCA是一种线性方法,不能处理非线性数据。特征向量的选择可能会导致信息丢失。对数据的缩放和中心化要求较高。