MATLAB SVD 教程:一步步带你掌握奇异值分解
奇异值分解(Singular Value Decomposition,简称 SVD)是线性代数中一种重要的矩阵分解方法,它在数据压缩、降噪、推荐系统、图像处理等众多领域都有着广泛的应用。本文将通过详细的步骤和 MATLAB 代码示例,带你深入理解 SVD 的原理和应用。
1. 什么是奇异值分解 (SVD)?
SVD 是一种将任意 $m \times n$ 矩阵 $A$ 分解为三个矩阵乘积的形式:
$A = U \Sigma V^T$
其中:
* $U$ 是一个 $m \times m$ 的正交矩阵(Orthogonal Matrix),其列向量是 $A A^T$ 的特征向量,称为左奇异向量。
* $\Sigma$ 是一个 $m \times n$ 的对角矩阵,其对角线上的元素是非负实数,称为奇异值(Singular Values),且通常按降序排列。对角线以外的元素均为 0。
* $V$ 是一个 $n \times n$ 的正交矩阵,其列向量是 $A^T A$ 的特征向量,称为右奇异向量。$V^T$ 是 $V$ 的转置。
核心思想: SVD 揭示了矩阵内部最重要的结构和信息。奇异值的大小反映了对应奇异向量方向上的数据变化强度,大的奇异值对应着数据中更重要的特征。
2. SVD 的数学原理(简要)
理解 SVD 的关键在于它与特征值分解的关系。
-
从 $A^T A$ 和 $A A^T$ 出发:
- $A^T A$ 是一个 $n \times n$ 的对称矩阵,它的特征值非负。
- $A A^T$ 是一个 $m \times m$ 的对称矩阵,它的特征值非负。
- 两者非零特征值是相同的。
-
右奇异向量 $V$:
- $V$ 的列向量是 $A^T A$ 的特征向量。
- 如果 $\lambda_i$ 是 $A^T A$ 的特征值,那么 $\sqrt{\lambda_i}$ 就是矩阵 $A$ 的奇异值。
-
左奇异向量 $U$:
- $U$ 的列向量是 $A A^T$ 的特征向量。
-
奇异值 $\Sigma$:
- $\Sigma$ 的对角线元素 $\sigma_i$ 是 $A^T A$(或 $A A^T$)的特征值的平方根,即 $\sigma_i = \sqrt{\lambda_i}$。
3. MATLAB 中的 SVD 函数
MATLAB 提供了内置函数 svd() 来执行奇异值分解。
语法:
[U, S, V] = svd(A)
A: 输入矩阵。U: 左奇异向量矩阵。S: 奇异值矩阵(对角矩阵)。V: 右奇异向量矩阵。
4. SVD 示例与 MATLAB 实现
让我们通过一个具体的例子来演示 SVD 在 MATLAB 中的应用。
例 1:基本 SVD 分解
假设我们有一个矩阵 $A$:
$A = \begin{pmatrix} 1 & 1 \ 0 & 1 \ 1 & 0 \end{pmatrix}$
MATLAB 代码:
“`matlab
% 定义输入矩阵 A
A = [1 1; 0 1; 1 0];
% 执行奇异值分解
[U, S, V] = svd(A);
% 显示结果
disp(‘原始矩阵 A:’);
disp(A);
disp(‘左奇异向量矩阵 U:’);
disp(U);
disp(‘奇异值矩阵 S:’);
disp(S);
disp(‘右奇异向量矩阵 V:’);
disp(V);
% 验证 SVD 分解的正确性:U * S * V’ 应该等于 A
A_reconstructed = U * S * V’;
disp(‘重构后的矩阵 A (U * S * V”):’);
disp(A_reconstructed);
% 检查重构误差
error = norm(A – A_reconstructed);
fprintf(‘重构误差 (norm(A – A_reconstructed)): %f\n’, error);
“`
运行结果分析:
你会看到 A_reconstructed 与原始矩阵 A 非常接近(误差接近于 0),这验证了 SVD 分解的正确性。
S 矩阵的对角线上的值就是奇异值,它们通常按降序排列。这些奇异值揭示了矩阵中不同方向上的数据“能量”或“重要性”。
5. SVD 的应用:数据降维(主成分分析 PCA 的核心)
SVD 最强大的应用之一是数据降维。通过保留最大的几个奇异值及其对应的奇异向量,我们可以近似原始矩阵,同时显著减少数据量。这正是主成分分析(PCA)的核心思想。
例 2:图像压缩
我们将使用 SVD 来压缩一张灰度图像。图像本质上是一个像素值矩阵。
步骤:
1. 加载图像并转换为灰度图。
2. 对图像矩阵执行 SVD。
3. 选择前 $k$ 个最大的奇异值和对应的奇异向量来重构图像。
4. 比较原始图像和压缩后的图像。
MATLAB 代码:
“`matlab
% 1. 加载图像并转换为灰度图
% 假设你有一张名为 ‘test_image.jpg’ 的图像文件在当前目录下
% 如果没有,可以使用 MATLAB 提供的示例图像
try
img_rgb = imread(‘test_image.jpg’); % 尝试加载用户图片
catch
warning(‘test_image.jpg not found, using example image.’);
img_rgb = imread(‘peppers.png’); % 使用MATLAB自带示例图片
end
% 转换为灰度图 (如果不是灰度图的话)
if size(img_rgb, 3) == 3
img_gray = rgb2gray(img_rgb);
else
img_gray = img_rgb;
end
% 将像素值转换为 double 类型以便进行数学运算
A = double(img_gray);
% 获取图像维度
[m, n] = size(A);
disp([‘原始图像尺寸: ‘, num2str(m), ‘x’, num2str(n)]);
% 2. 对图像矩阵执行 SVD
tic; % 计时开始
[U, S, V] = svd(A);
toc; % 计时结束
% 3. 选择不同数量的奇异值进行重构
k_values = [1, 5, 20, 50, 100]; % 尝试不同的 k 值
figure;
subplot(2, 3, 1);
imshow(uint8(A));
title(‘原始图像’);
for i = 1:length(k_values)
k = k_values(i);
% 截取前 k 个奇异值和对应的奇异向量
U_k = U(:, 1:k);
S_k = S(1:k, 1:k);
V_k = V(:, 1:k);
% 重构图像
A_k_reconstructed = U_k * S_k * V_k';
subplot(2, 3, i + 1);
imshow(uint8(A_k_reconstructed)); % 转换回 uint8 显示
title(['重构图像 (k = ', num2str(k), ')']);
% 计算压缩率(近似)
% 原始数据量: m*n
% 压缩后数据量: m*k + k + k*n (U_k, S_k, V_k)
% 忽略 S_k 对角线以外的0,实际储存 k 个奇异值
original_data_points = m * n;
compressed_data_points = m * k + k + n * k;
fprintf('k = %d, 压缩数据点: %d, 原始数据点: %d, 压缩率: %.2f%%\n', ...
k, compressed_data_points, original_data_points, ...
(1 - compressed_data_points / original_data_points) * 100);
end
sgtitle(‘SVD 图像压缩示例’); % 设置整个图窗的标题
“`
实验与观察:
- 你会发现,随着
k值的增加,重构的图像越来越接近原始图像。 - 即使
k相对较小,我们也能得到一个可识别的图像,这说明 SVD 成功地捕获了图像的主要特征。 - 通过牺牲一部分图像质量,我们实现了显著的数据压缩。
6. SVD 的其他应用场景
- 推荐系统: SVD 可以用于用户-物品评分矩阵的分解,从而发现潜在的用户兴趣和物品特征,实现个性化推荐(例如 Netflix 挑战)。
- 自然语言处理 (NLP): 潜在语义分析 (Latent Semantic Analysis, LSA) 利用 SVD 来发现文档和词语之间的潜在语义关系,解决同义词和多义词问题。
- 信号处理: SVD 可以用于信号去噪,通过去除小的奇异值对应的分量来滤除噪声。
- 计算机视觉: 人脸识别(Eigenfaces)、图像去模糊等。
7. 注意事项
- 计算成本: 对大型矩阵进行 SVD 分解是计算密集型的操作。对于非常大的稀疏矩阵,通常会使用迭代方法来近似计算SVD。
- 数值稳定性: SVD 是数值稳定的,这使其成为许多应用的首选方法。
- 唯一性: 奇异值是唯一的,但奇异向量不一定是唯一的(特别是当奇异值重复时)。然而,对于 $U \Sigma V^T$ 的整体重构结果是唯一的。
总结
奇异值分解 (SVD) 是一个强大且用途广泛的数学工具。通过本教程,你应该已经对 SVD 的原理、在 MATLAB 中的实现以及它在数据降维(特别是图像压缩)中的应用有了清晰的理解。掌握 SVD 将为你在数据科学、机器学习和信号处理等领域打开新的大门。