全部版块 我的主页
论坛 数据科学与人工智能 数据分析与数据科学 MATLAB等数学软件专版
251 0
2025-12-09

数据预处理中的归一化与标准化:MATLAB 实现详解

在数据分析、机器学习和模型训练中,数据归一化(Normalization)与标准化(Standardization)是至关重要的预处理步骤。它们能够消除不同特征间的量纲差异,提升模型收敛速度与预测精度。MATLAB 提供了灵活的手动计算方式以及高效的内置函数,适用于矩阵、表格、时间序列等多种数据类型。本文将系统讲解两者的原理、实现方法、实战应用及常见注意事项。

一、基本概念对比:归一化 vs 标准化

1.1 归一化(Min-Max Scaling)

核心原理: 将原始数据线性映射到指定区间,通常为 [0, 1] 或 [-1, 1],以统一数值范围。其数学表达式如下:

Xnorm = (X - Xmin) / (Xmax - Xmin)

若目标区间为 [-1, 1],则公式调整为:

Xnorm = 2 × (X - Xmin) / (Xmax - Xmin) - 1

[0,1]
[-1,1]

适用情况包括:

  • 对输入范围有严格限制的模型(如神经网络输入层、图像像素处理);
  • 数据分布较为均匀且无显著极值;
  • 需要保留原始数据相对比例关系的任务(例如聚类分析、推荐系统中的协同过滤)。

1.2 标准化(Z-Score Normalization)

核心原理: 将数据转换为均值为 0、标准差为 1 的分布,突出偏离中心的程度。计算公式为:

Xstd = (X - μ) / σ

其中,μ 表示样本均值,σ 为样本标准差。

[-1,1]

典型应用场景:

  • 存在异常值或极端波动的数据(如传感器读数、金融指标);
  • 对数据分布敏感的算法(如线性回归、支持向量机 SVM、主成分分析 PCA);
  • 需消除单位影响同时保留整体分布形态的统计建模任务。

1.3 主要区别总结

方法 核心特性 抗异常值能力 适合的数据分布
归一化 结果范围固定,依赖最小值和最大值 弱(受极值影响大) 近似均匀分布、无明显离群点
标准化 均值为0,标准差为1,基于统计参数 强(对异常值鲁棒性较好) 接近正态分布,允许存在极端值

二、MATLAB 中的实现方式:手动编码与内置函数结合

2.1 数据预处理准备:处理缺失值与异常值

在进行归一化或标准化前,必须先清理数据中的缺失项和异常点,否则会导致缩放偏差。

% 示例:包含缺失值的温度传感器数据
data = [25.3, 26.1, NaN, 27.8, 30.5, 100.2, 28.9, 29.4];

% 1. 缺失值填充(使用忽略 NaN 的均值)
data(isnan(data)) = mean(data, 'omitNaN');

% 2. 异常值检测与修正(采用3倍标准差准则)
mu = mean(data);
sigma = std(data);
outlier_idx = abs(data - mu) > 3*sigma;
data(outlier_idx) = median(data); % 使用中位数替代异常值

2.2 归一化(Min-Max Scaling)的具体实现

方法一:手动实现(便于控制细节)

通过基础运算完成按列归一化,适用于自定义需求。

% 构造原始数据(每行代表一个样本,每列为一个特征)
X = [10, 200, 5;
     15, 300, 8;
     5, 100, 3;
     20, 400, 10];

% 计算各列的最小值与最大值
X_min = min(X);
X_max = max(X);

% 执行 Min-Max 归一化至 [0,1]
X_norm = (X - X_min) ./ (X_max - X_min);

% 显示结果
disp('原始数据:'); disp(X);
disp('归一化后数据:'); disp(X_norm);
原始数据:
    10   200     5
    15   300     8
     5   100     3
    20   400    10

归一化后数据:
    0.3333    0.3333    0.2857
    0.6667    0.6667    0.7143
    0         0         0
    1.0000    1.0000    1.0000
方法二:使用内置函数 mapminmax

MATLAB 提供了专用函数 mapminmax,可快速实现归一化,并支持自定义输出范围。

% 对数据进行归一化,默认映射到 [0,1]
[X_norm, ps] = mapminmax(X'); % 注意:该函数要求特征在行方向,需转置
X_norm = X_norm'; % 转回原格式
mapminmax

2.3 标准化的实现方法

方法一:手动实现(理解底层逻辑)

利用均值和标准差自行计算,有助于掌握标准化过程。

% 原始数据同上
mu = mean(X);
sigma = std(X);

% 按列执行 Z-Score 标准化
X_std = (X - mu) ./ sigma;

% 输出查看
disp('标准化后数据:'); disp(X_std);
方法二:调用内置函数 zscore

MATLAB 的 zscore 函数可直接完成标准化操作,简洁高效。

% 直接调用 zscore(默认按列标准化)
X_std = zscore(X);

2.4 表格型数据的归一化与标准化

对于表格结构(table 类型),可通过变量提取后分别处理,再合并回表。

% 创建示例表格
T = table([1;2;3], [100;200;300], [5.1;6.3;7.8], 'VariableNames', {'Age','Income','Score'});

% 提取数值列并标准化
numeric_cols = varfun(@isnumeric, T, 'OutputFormat', 'uniform');
T_numeric = T{:, numeric_cols};

% 进行标准化
T_normalized = zscore(T_numeric);

% 写回新表格
T{: , numeric_cols} = num2cell(T_normalized);

三、实际案例:在回归模型中的应用

在构建多元线性回归或岭回归模型时,若各特征尺度差异较大(如年龄 vs 收入),不进行归一化/标准化可能导致梯度下降缓慢或权重失衡。通过对训练集进行标准化处理,并将相同的参数应用于测试集,可显著提高模型稳定性与泛化能力。

四、常见问题与应对策略

4.1 避免混用训练集与测试集的统计量

应仅使用训练集的最小值/最大值或均值/标准差来处理测试集,防止信息泄露。例如,在使用 mapminmax 时保存参数 ps,并在测试集上复用。

4.2 常量特征无需处理

当某一特征的所有值相同(方差为0),标准化会导致除零错误,此类特征应提前识别并剔除或单独处理。

4.3 注意数据维度的方向(行 vs 列)

MATLAB 多数函数默认按列操作。若数据组织为“每行为一样本”,则需确认函数是否需要转置输入,避免误操作。

4.4 结果还原:反归一化与反对标准化

模型输出常需恢复至原始尺度以便解释。可借助保存的极值或统计参数进行逆变换:

  • 反归一化:X = Xnorm × (Xmax - Xmin) + Xmin
  • 反对标准化:X = Xstd × σ + μ

五、进阶技巧:大规模数据的批量处理

面对海量数据时,建议采用分块读取 + 参数缓存的方式进行归一化/标准化。先从训练数据中提取全局统计量(如最大值、最小值、均值、标准差),然后逐批次应用相同规则处理,确保一致性的同时降低内存压力。

2.3 标准化(Z-Score)实现

方法1:手动实现(理解核心逻辑)

% 按列(特征)进行标准化
X_mu = mean(X);           % 计算每列的均值
X_sigma = std(X);         % 计算每列的标准差
X_std = (X - X_mu) ./ X_sigma;
disp('标准化后数据:'); disp(X_std);

执行结果:

标准化后数据:
   -0.37796   -0.37796   -0.43301
    0.37796    0.37796    0.51962
   -1.13389   -1.13389   -1.08253
    1.13389    1.13389    0.99592

方法2:使用内置函数

MATLAB 提供了 zscore 函数,可直接完成标准化处理,无需手动计算均值与标准差。

% 基础标准化(默认方式)
X_std = zscore(X);

% 处理包含缺失值的数据
X_with_nan = [10, 200, NaN; 15, 300, 8; 5, 100, 3];
X_std_nan = zscore(X_with_nan, 0, 'omitNaN'); % 使用n-1作为分母,并忽略NaN

核心参数说明:

  • 第二个参数:0 表示使用无偏估计(除以 n-1),1 表示有偏估计(除以 n);
  • 'omitNaN':在存在缺失值时有效处理,防止输出全为 NaN。
zscore

归一化到 [-1, 1] 区间并保存参数

对原始数据进行归一化处理,并转回原始维度结构:

X_norm = X_norm'; % 转置恢复原始维度

% 将数据映射至 [-1, 1] 范围
[X_norm_neg, ps_neg] = mapminmax(X', -1, 1);
X_norm_neg = X_norm_neg';

关键步骤:保存归一化过程中生成的参数,以便后续对新数据使用相同的变换规则。

% 保存归一化参数(用于测试阶段)
save('norm_params.mat', 'ps');

核心说明:

ps

保存的是训练数据中的最大最小值等归一化参数。新来的测试数据必须使用同一组参数进行转换,避免引入信息泄露问题。

测试数据的归一化示例

% 加载之前保存的归一化参数
load('norm_params.mat');

% 示例测试样本
X_test = [12, 250, 6];

% 应用相同参数进行归一化
X_test_norm = mapminmax('apply', X_test', ps)';

2.4 表格数据的归一化与标准化处理

实际项目中,数据常以表格形式存储(如 Excel 文件)。需先提取数值列,再进行标准化或归一化操作。

% 读取传感器数据表格
data_table = readtable('sensor_data.xlsx');

% 提取前三个数值型特征列
X_table = table2array(data_table(:, 1:3));

% 对特征进行标准化
X_table_std = zscore(X_table);

% 将标准化后的数据写回表格
data_table_std = data_table;
data_table_std(:, 1:3) = array2table(X_table_std);

% 保存处理后的结果
writetable(data_table_std, 'sensor_data_std.xlsx');
table

三、实战案例:归一化/标准化在线性回归模型中的应用

以房价预测任务为例,比较是否进行标准化对模型性能的影响。

% 1. 加载 MATLAB 内置房价数据集
load houseprices.mat;

% 提取输入特征(地块面积、卧室数量、浴室数量)和目标变量(售价)
X = [LotArea, BedroomAbvGr, FullBath];
y = SalePrice;

% 2. 数据预处理
% 对特征进行标准化
X_std = zscore(X);

% 对标签(房价)进行归一化,并保存参数用于后续反变换
[y_norm, ps_y] = mapminmax(y');
y_norm = y_norm';

% 3. 构建线性回归模型
% 原始数据训练的模型
model_raw = fitlm(X, y);

% 标准化后数据训练的模型
model_std = fitlm(X_std, y_norm);

% 4. 模型评估 —— 使用均方误差(MSE)
y_pred_raw = predict(model_raw, X);
mse_raw = mean((y - y_pred_raw).^2);

y_pred_std = predict(model_std, X_std);
% 将预测结果还原到原始价格尺度
y_pred_std_ori = mapminmax('reverse', y_pred_std', ps_y)';
mse_std = mean((y - y_pred_std_ori).^2);

% 输出评估结果
disp(['标准化前MSE:', num2str(mse_raw)]);
disp(['标准化后MSE:', num2str(mse_std)]);

结果分析:
标准化后的模型 MSE 显著低于未标准化的情况。原因在于原始特征之间量纲差异大(例如“地块面积”为数千单位,“卧室数”仅为个位整数),导致优化过程不稳定、权重分配失衡。通过标准化使所有特征处于相近数值范围,提升了模型收敛速度与拟合精度。

四、常见误区与应对策略

4.1 避免混用训练集与测试集的统计信息

错误做法:将训练集和测试集合并后再统一进行归一化或标准化,这会导致测试集的信息“提前”被模型知晓,造成信息泄露,影响评估真实性。

正确做法:仅基于训练集计算均值、标准差或最大最小值,并将这些参数应用于测试集的变换中,确保测试过程完全独立。

1
'omitNaN'

正确做法:使用训练集的最值、均值或标准差对测试集进行归一化或标准化处理,确保数据分布一致性。以下是具体实现步骤:

% 划分训练集(70%)和测试集(30%)
idx = randperm(size(X,1));
train_idx = idx(1:round(0.7*size(X,1)));
test_idx = idx(round(0.7*size(X,1))+1:end);
X_train = X(train_idx, :);
X_test = X(test_idx, :);

% 基于训练集计算归一化所需参数
X_train_min = min(X_train);
X_train_max = max(X_train);

% 对训练集执行归一化
X_train_norm = (X_train - X_train_min)./(X_train_max - X_train_min);

% 使用训练集的参数对测试集进行归一化
X_test_norm = (X_test - X_train_min)./(X_train_max - X_train_min);

4.2 常量特征的处理:无需归一化或标准化

对于所有值相同的常量列,其最大值与最小值之差为0,若直接进行归一化会导致除以零错误。因此,应在预处理阶段先行剔除此类特征。

% 检测是否存在常量列
constant_cols = std(X) == 0;

% 删除常量特征列
X_clean = X(:, ~constant_cols);

% 对清洗后的数据进行归一化处理
X_clean_norm = mapminmax(X_clean')';

4.3 注意数据处理的方向:按特征而非样本

常见误区是按行(即每个样本自身)进行归一化,这会破坏不同特征之间的量纲对比关系。正确的做法应始终针对列方向——也就是每一个特征维度独立进行标准化或归一化。

核心原则:归一化/标准化操作应在特征维度(列)上进行,而不是在样本维度(行)上执行。

4.4 预测结果还原:反归一化与反标准化

模型输出通常处于归一化空间中,需将其转换回原始量纲以便解释。利用训练阶段保存的参数即可完成逆变换。

% Min-Max 归一化的逆操作
X_ori = X_norm .* (X_max - X_min) + X_min;

% Z-Score 标准化的逆操作
X_ori_std = X_std .* X_sigma + X_mu;

% 使用 mapminmax 函数进行反向转换
X_ori_map = mapminmax('reverse', X_norm', ps)';

五、进阶技巧:大数据集的批量处理策略

当面对大规模数据(例如超过十万行)时,一次性加载全部数据可能引发内存溢出问题。推荐采用分块读取的方式逐步处理。

% 创建表格文本数据存储对象
ds = tabularTextDatastore('big_data.csv');

% 设置每次读取的数据块大小
ds.ReadSize = 1000; % 每次读取1000行

% 初始化用于存储全局最值的变量
all_min = [];
all_max = [];
first_chunk = true;

% 第一次遍历:统计所有数据块中的全局最小值和最大值

while hasdata(ds)
   chunk = read(ds);
   X_chunk = table2array(chunk);
   if first_chunk
      all_min = min(X_chunk);
      all_max = max(X_chunk);
      first_chunk = false;
   else
      all_min = min([all_min; min(X_chunk)]);
      all_max = max([all_max; max(X_chunk)]);
   end
end

% 完成后重置数据读取位置,准备第二次遍历
reset(ds);

% 创建空的目标文件用于存储结果
writetable(table(), 'normalized_big_data.csv');

% 第二次遍历:使用全局最值对每一块数据进行归一化并追加写入文件

while hasdata(ds)
   chunk = read(ds);
   X_chunk = table2array(chunk);
   X_chunk_norm = (X_chunk - all_min)./(all_max - all_min);
   chunk_norm = array2table(X_chunk_norm);
   % 以追加模式写入归一化后的数据块
   writetable(chunk_norm, 'normalized_big_data.csv', 'WriteMode', 'append');
end

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

相关推荐
栏目导航
热门文章
推荐文章

说点什么

分享

扫码加好友,拉您进群
各岗位、行业、专业交流群