目录
一、概述
1.PCA
- PCA (Principal Component Analysis) 是一种常用的数据降维算法,用于对高维数据进行降维和特征提取。它的主要思想是通过对数据的协方差矩阵进行特征值分解,选择前 k 个特征值最大的特征向量作为新的主成分,将原始数据投影到主成分空间,从而实现数据降维。
2.PCA特点
- PCA 常用于数据降维、数据可视化、数据压缩等场景,其特点是可以有效的降低数据维度,保留数据的主要特征。
3.主成分
- 将原始高维向量通过投影矩阵,投射到低维空间,这些向量称为主成分(PCs),具有无关性、正交的特点。重要的是这些向量的数量要远小于高维空间的维度。
4.主成分的代数定义
- 给定n个样本(每个样本维度为p维)
-
定义为样本在第一主成分/主方向上的投影:
-
其中,,
-
目标是找到a1,使z1的方差最大
二、PCA步骤
- 中心化:将数据的每一个特征列减去该列的平均值,使得每一个特征的均值为 0。
- 协方差:计算样本的协方差矩阵,该矩阵表示各个特征之间的关系。
- 特征分析:对协方差矩阵进行特征分析,得到特征值和特征向量。特征向量表示了新的坐标轴的方向,特征值表示了新坐标轴的方差。计算S的特征向量:
- 降维:选择特征值较大的特征向量,构造新的坐标系,将原始数据投影到新的坐标系上,从而达到降维的目的。
- 这些步骤通过计算的过程可以得到一个主成分的矩阵,该矩阵的列表示了新的坐标轴,行表示了每一个样本在新坐标系上的坐标。
- 例子(如图)
1、2、
3、
三、Python代码
1.读取数据
import os
from pyntcloud import PyntCloud
import open3d as o3d
import numpy as np
def main():
root_dir = r"..\modelnet40_normal_resampled\modelnet40_normal_resampled"
shapenames = "modelnet40_shape_names.txt"
with open (os.path.join(root_dir, shapenames)) as f:
shape_name_list = f.readlines() # .readlines一次性读取所有数据,按行存成list
for item in shape_name_list:
name = item.strip()
file_path_name = os.path.join(root_dir, name) + r"\\{}_0001.txt".format(name) # 只读取每个类别的第一个点云数据
point_cloud_pynt = PyntCloud.from_file(file_path_name, sep=",", names=["x", "y", "z", "nx", "ny", "nz"])
point_cloud_o3d = point_cloud_pynt.to_instance("open3d", mesh=False) # 将数据转成open3d格式,不生成网格数据,只转为点云数据
o3d.visualization.draw_geometries(([point_cloud_o3d])) # 可视化原始点云数据
points = point_cloud_pynt.points # .points之后是DataFrame格式
points_loc = np.array(points.loc[:, ["x", "y", "z"]]) # .loc通过指定列名称来索引
# points_loc = np.array(points.iloc[:, [0, 1, 2]]) # .iloc通过指定列索引值来索引
if __name__ == "__main__":
main()
函数解释: os.path.join():用于路径拼接文件路径,可以传入多个路径
2.PCA实现
def PCA(data, k):
data_new = np.array(data - data.mean(axis=0)) # 去中心化
H = np.dot(data_new.T, data_new) / (data_new.shape[0] - 1) # 计算协方差矩阵,矩阵相乘后除以[点数-1]
# H = np.cov(data.T) # 计算结果维度和输入数据行数保持一致,因此输入数据要进行转置(np.cov输入数据去不去中心化结果一样)
# 使用SVD分解
U, S, V = np.linalg.svd(H)
sort_index = np.argsort(S)[::-1] # np.argsort()返回排序后的索引顺序,这里按照降序排列
select_eigen_vecs = U[:, sort_index[:k]] # 求前k大的奇异值对应的特征向量
# 计算PCA后的结果,并可视化
points_after_PCA = np.dot(data_new, select_eigen_vecs) # 要使用去中心化的数据进行运算!!!
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(points_after_PCA)
o3d.visualization.draw_geometries([pcd])
return select_eigen_vecs
K = 3 # PCA降维目标维度
Vecs = PCA(points_loc, K)
- 注意:使用矩阵相乘的形式计算协方差矩阵时,记得要除以[点数-1]
- 协方差矩阵公式: ,
- 函数解释:np.argsort()返回排序后的索引顺序,这里按照降序排列
3. 结果呈现
- 原始点云如左下,PCA后的点云如右下
实验分析:
- PCA实现过程中不同的协方差矩阵计算方式(直接代入公式求解、调用库函数),对结果的影响只是影响处理之后数据的方向;当PCA算法没有改变数据维度时,本质只是将点云变换到了更容易辨别出目标类别的方向上(即方差最大的几个方向)。
四、实验总结
PCA 算法的一个重要优点是可以有效的降低数据的维度,降低数据的维数对于降低算法的复杂度和避免过拟合都有很重要的作用。但为了降低数据的维度,可能会导致一定的信息损失。所以在使用PCA时,要根据实际情况权衡利弊,结合其他算法一起使用。