Skip to content

MATLAB - 数据归一化

数据归一化(或称特征缩放)是数据分析和机器学习中一个关键的预处理步骤。它涉及将数据集的特征转换到共同的尺度上,同时不扭曲值范围内的差异。MATLAB 的 normalize 函数提供了一种强大而灵活的方式来执行此任务。

数据归一化至关重要,原因如下:

  • 算法性能:许多机器学习算法(如支持向量机、k近邻以及基于梯度下降的算法,如线性回归和神经网络)在特征尺度差异巨大时,性能会很差或收敛缓慢。例如,范围从0到100,000的特征会主导范围从0到1的特征。
  • 特征可比性:归一化使所有特征处于同一水平,从而实现有意义的比较和组合。
  • 改善可视化:数据缩放可以更容易地在单个图上可视化变量之间的关系。

让我们使用 normalize 函数来探索最常见的方法。

% 让我们创建一个具有不同尺度下两个特征的样本数据集
% 特征 1: '年龄' (例如,20-65)
% 特征 2: '薪水' (例如,5万-15万)
data = [25, 60000;
45, 90000;
60, 125000;
22, 52000;
38, 75000];

该方法将数据重新缩放,使其均值 (μ) 为 0,标准差 (σ) 为 1。公式为 z = (x - μ) / σ。

  • 用例:这是最常见的方法,当您的数据服从高斯(正态)分布时效果很好。与最小-最大缩放相比,它受异常值的影响较小。
  • MATLAB 语法:normalize(data, 'zscore')
% 使用Z-分数标准化数据
normalized_zscore = normalize(data, 'zscore');
disp('Original Data:');
disp(data);
disp('Z-score Normalized Data:');
disp(normalized_zscore);
% 验证新数据的均值和标准差 (应接近0和1)
fprintf('Mean of normalized data: [%.2f, %.2f]\n', mean(normalized_zscore));
fprintf('Std of normalized data: [%.2f, %.2f]\n', std(normalized_zscore));

此方法将数据重新缩放到一个固定范围,通常是 [0, 1]。公式为 x_scaled = (x - min(x)) / (max(x) - min(x))。

  • 用例:适用于期望输入在有界区间内的算法,例如某些神经网络。在图像处理中也很常见,其中像素值缩放到 [0, 1]。请注意,它对异常值很敏感。
  • MATLAB 语法:normalize(data, 'range')
% 将数据缩放到 [0, 1] 范围
normalized_range = normalize(data, 'range');
disp('Min-Max Scaled Data:');
disp(normalized_range);

您也可以指定自定义范围,例如 [-1, 1]:

% 缩放到 [-1, 1] 范围
normalized_custom_range = normalize(data, 'range', [-1, 1]);

此方法对每个样本(行)进行缩放,使其具有单位范数(例如,L2-范数或欧几里得长度为 1)。这常用于文本分析或当数据向量的方向比其大小更重要时。

  • 用例:使用 TF-IDF 的文本分类,聚类算法。
  • MATLAB 语法:normalize(data, 'norm', p),其中 p 是范数(例如,L2 范数为 2)。
% 注意:我们需要指定操作的维度为行 (dim=2)
normalized_norm = normalize(data, 2, 'norm', 2);
disp('L2-Norm Scaled Data (by row):');
disp(normalized_norm);
% 验证每行的L2范数 (应为1)
disp('L2 Norms of each row:');
disp(vecnorm(normalized_norm, 2, 2));

最佳实践:处理训练集和测试集

Section titled “最佳实践:处理训练集和测试集”

一个常见的错误是在将整个数据集拆分为训练集和测试集之前对其进行归一化。这会导致数据泄露,即测试集的信息(例如其最小/最大值)泄露到训练过程中,从而导致过于乐观的性能估计。

正确的方法是仅从训练数据中计算缩放参数(均值/标准差、最小/最大值),然后将相同的变换应用于测试数据。normalize 函数并非为此两步过程而设计,因此我们需要手动执行此操作。

% 1. 拆分数据 (用于演示)
trainData = data(1:3, :);
testData = data(4:5, :);
% 2. 仅从训练数据计算缩放参数
mu = mean(trainData);
sigma = std(trainData);
% 3. 将变换应用于训练集和测试集
trainData_norm = (trainData - mu) ./ sigma;
testData_norm = (testData - mu) ./ sigma; % 使用来自训练数据的mu/sigma!
disp('Correctly Normalized Training Data:');
disp(trainData_norm);
disp('Correctly Normalized Test Data:');
disp(testData_norm);