概念

主成分分析(Principle Component Analysis,缩写PCA)是一种特征降维技术,也是一种无监督学习算法。另外两种较为常用的降维技术是t-SNE和自编码器。PCA能从冗余特征中提取主要成分,在不太损失模型质量的情况下,提升模型训练速度。

PCA的执行流程如下,假设需要将数据降低到k维: 1. 特征标准化,平衡各个特征值 2. 计算协方差矩阵Σ 3. 奇异值分解(SVD),求取Σ的特征向量 4. 从U中取出前k个左奇异向量,构成一个约减矩阵 5. 计算新的特征向量

在机器学习中,一定谨记不要提前优化,只有当算法运行效率不尽如如人意时,再考虑使用PCA或者其他特征降维手段来提升训练速度。

TensorFlow实现

首先从文件中读取训练数据,之后计算相关内容。

data = scio.loadmat('ex7data1.mat')
train_data = data['X']
X = tf.Variable(train_data) # 读取并载入

means, variance = tf.nn.moments(X, axes=0) # 计算各个特征的均值,方差
normalized_data = tf.subtract(train_data, means) / tf.sqrt(variance) # 标准化

m = tf.cast(tf.shape(normalized_data)[0], tf.float64) # 将样例数m转换为float类型,防止下一步报错
cov = tf.matmul(tf.transpose(normalized_data), normalized_data) / m # 计算协方差矩阵

使用TensorFlow内置的函数进行奇异值分解,其中需要用到的输出是左奇异向量u,从中取出前k个向量。这里需要注意的一点是,在测试时我发现TensorFlow计算出来的U和Numpy内置函数计算出来的U不同,需要添加负号才能等同。查阅资料后发现,这属于内置函数的处理问题,并不影响求解SVD的正确性。

s, u, v = tf.svd(cov)
u_reduce = u[:, :k] * -1 # 添加负号修正
z = tf.matmul(X, u_reduce) # 计算特征向量

因为PCA仅保留了特征的主成分,所以PCA是一种有损的压缩方式,还原特征需进行如下计算:

x_approx = tf.matmul(z, tf.transpose(u_reduce))

最终还原出的数据如下图所示,可以看出二维的特征值已经降到了一维,形成一条直线。

参考资料: 奇异值分解svd PCA(主成分分析)