手把手图解:用Python把‘能量守恒’和‘勾股定理’画出来,理解机器学习降维不丢信息的本质
手把手图解用Python把‘能量守恒’和‘勾股定理’画出来理解机器学习降维不丢信息的本质在机器学习领域降维技术如PCA主成分分析和SVD奇异值分解常被用来处理高维数据。但你是否好奇过为什么这些方法能在减少数据维度的同时几乎不丢失关键信息答案藏在数学中的能量守恒和勾股定理里。本文将带你用Python代码从几何视角直观理解这一核心原理。我们将使用NumPy和Matplotlib从二维数据点出发通过可视化展示正交变换如何保持数据的能量方差不变。这种动手实践的方式不仅能加深你对PCA原理的理解还能让你真正掌握降维技术的数学本质。1. 准备工作与环境配置在开始之前确保你的Python环境已安装以下库import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D如果你尚未安装这些库可以使用pip快速安装pip install numpy matplotlib提示建议使用Jupyter Notebook进行本教程的实践它能实时显示图形输出方便交互式学习。2. 理解数据能量的数学定义在信号处理和机器学习中能量这一概念与物理学中的定义有所不同。这里我们定义数据点的能量为其到原点距离的平方能量 x₁² x₂² ... xn²这与勾股定理在多维空间的扩展形式完全一致。让我们用代码生成一些二维数据点并计算它们的能量# 生成随机二维数据点 np.random.seed(42) data np.random.randn(100, 2) * 5 # 100个点标准差为5 # 计算每个点的能量 energies np.sum(data**2, axis1) total_energy np.sum(energies) print(f总能量: {total_energy:.2f})3. 可视化原始数据及其能量分布为了更好地理解我们先绘制这些数据点plt.figure(figsize(10, 6)) plt.scatter(data[:, 0], data[:, 1], cenergies, cmapviridis) plt.colorbar(label单个点能量) plt.axhline(0, colorblack, linestyle--) plt.axvline(0, colorblack, linestyle--) plt.title(二维数据点及其能量分布) plt.xlabel(X轴) plt.ylabel(Y轴) plt.grid(True) plt.show()你会看到点越远离原点其颜色越亮能量越高。所有点的能量总和就是我们要关注的守恒量。4. 正交变换与能量守恒正交变换如旋转是PCA的核心。这类变换有一个重要特性保持向量的长度即能量不变。让我们创建一个旋转矩阵并应用它# 创建旋转矩阵30度 theta np.radians(30) rotation_matrix np.array([ [np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)] ]) # 应用旋转 rotated_data data rotation_matrix # 计算旋转后能量 rotated_energies np.sum(rotated_data**2, axis1) rotated_total_energy np.sum(rotated_energies) print(f旋转后总能量: {rotated_total_energy:.2f})比较旋转前后的总能量你会发现它们几乎相同可能有微小差异来自浮点运算。这就是能量守恒的体现。5. 从二维到三维的扩展理解为了更深入理解我们扩展到三维空间。首先生成一些三维数据# 生成三维数据 np.random.seed(42) data_3d np.random.randn(100, 3) * 5 # 计算能量 energies_3d np.sum(data_3d**2, axis1) total_energy_3d np.sum(energies_3d) print(f三维数据总能量: {total_energy_3d:.2f})然后创建一个三维旋转矩阵并应用# 创建绕Z轴旋转45度的矩阵 theta_z np.radians(45) rotation_z np.array([ [np.cos(theta_z), -np.sin(theta_z), 0], [np.sin(theta_z), np.cos(theta_z), 0], [0, 0, 1] ]) # 应用旋转 rotated_3d data_3d rotation_z # 验证能量守恒 rotated_energies_3d np.sum(rotated_3d**2, axis1) rotated_total_energy_3d np.sum(rotated_energies_3d) print(f旋转后三维总能量: {rotated_total_energy_3d:.2f})6. 连接PCA寻找最大能量方向PCA的核心思想是找到数据中能量方差最大的方向。让我们用代码实现一个简化版PCA# 计算协方差矩阵 cov_matrix np.cov(data.T) # 计算特征值和特征向量 eigenvalues, eigenvectors np.linalg.eig(cov_matrix) # 按特征值大小排序 sorted_indices np.argsort(eigenvalues)[::-1] eigenvalues eigenvalues[sorted_indices] eigenvectors eigenvectors[:, sorted_indices] print(特征值各主成分的能量:, eigenvalues) print(特征向量主成分方向:\n, eigenvectors)第一主成分方向就是能量最大的方向。我们可以将数据投影到这个方向上# 投影到第一主成分 principal_component eigenvectors[:, 0] projected_data data principal_component # 计算投影后能量 projected_energy np.sum(projected_data**2) print(f第一主成分保留能量: {projected_energy:.2f}) print(f能量保留比例: {projected_energy/total_energy:.2%})7. 完整可视化从原始数据到PCA降维最后让我们将所有步骤可视化plt.figure(figsize(12, 6)) # 原始数据 plt.subplot(1, 2, 1) plt.scatter(data[:, 0], data[:, 1], alpha0.6) plt.quiver(0, 0, eigenvectors[0, 0]*eigenvalues[0], eigenvectors[1, 0]*eigenvalues[0], anglesxy, scale_unitsxy, scale1, colorr, labelPC1) plt.quiver(0, 0, eigenvectors[0, 1]*eigenvalues[1], eigenvectors[1, 1]*eigenvalues[1], anglesxy, scale_unitsxy, scale1, colorg, labelPC2) plt.title(原始数据与主成分方向) plt.legend() # 投影后的数据 plt.subplot(1, 2, 2) plt.scatter(projected_data, np.zeros_like(projected_data), alpha0.6) plt.title(数据在第一主成分上的投影) plt.tight_layout() plt.show()这个可视化清晰地展示了PCA如何找到数据中能量最大的方向并将数据投影到这个方向上同时最大限度地保留了原始数据的能量方差。