此代码接受大小为 的数据矩阵M x N
,其中M
是来自该矩阵的一个数据样本的维N
数,是样本总数。因此,该矩阵的一列是一个数据样本。数据样本都是水平堆叠的,是列。
现在,此代码的真正目的是获取矩阵的所有列并对数据进行标准化/规范化,以使每个数据样本都表现出零均值和单位方差。这意味着在这个变换之后,如果你在这个矩阵中找到任何一列的平均值,它会是 0,方差会是 1。这是在统计分析、机器学习和计算机视觉中标准化值的一种非常标准的方法.
这实际上来自统计分析中的z 分数。具体来说,归一化方程为:

给定一组数据点,我们用这些数据点的平均值减去相关值,然后除以各自的标准差。您如何称呼此代码如下。给定这个矩阵,我们称之为X
,有两种方法可以调用这个代码:
- 方法#1:
[X, mean_X, std_X] = standardize(X);
- 方法#2:
[X, mean_X, std_X] = standardize(X, mu, sigma);
第一种方法自动推断 的每列的平均值和 的每列X
的标准差X
。 mean_X
并且std_X
都将返回1 x N
向量,为您提供矩阵中每一列的均值和标准差X
。第二种方法允许您为 的每一列手动指定平均值 ( mu
) 和标准差 ( ) 。这可能用于调试,但在这种情况下,您可以同时指定和作为向量。返回的和与和相同。sigma
X
mu
sigma
1 x N
mean_X
std_X
mu
sigma
恕我直言,代码写得有点糟糕,因为你当然可以实现这个向量化,但代码的要点是,X
如果我们使用方法#1,它会找到矩阵每一列的平均值,复制这个向量以便它变成一个M x N
矩阵,然后我们用 减去这个矩阵X
。这将减去每列各自的平均值。我们还在平均减法之前计算每列的标准偏差。
一旦我们这样做了,然后我们X
通过将每列除以其各自的标准偏差来标准化我们。顺便说一句,做std_X(:, i)
是多余的,因为std_X
它已经是一个1 x N
向量。 std_X(:, i)
表示抓取i
第 th列的所有行。如果我们已经有一个1 x N
向量,这可以简单地替换为std_X(i)
- 对我来说有点矫枉过正。
方法 #2 与方法 #1 执行相同的操作,但我们为X
.
出于文档的考虑,这就是我对代码的注释方式:
function [X, mean_X, std_X] = standardize(varargin)
switch nargin %// Check how many input variables we have input into the function
case 1 %// If only one variable - this is the input matrix
mean_X = mean(varargin{1}); %// Find mean of each column
std_X = std(varargin{1}); %// Find standard deviation of each column
%// Take each column of X and subtract by its corresponding mean
%// Take mean_X and duplicate M times vertically
X = varargin{1} - repmat(mean_X, [size(varargin{1}, 1) 1]);
%// Next, for each column, normalize by its respective standard deviation
for i = 1:size(X, 2)
X(:, i) = X(:, i) / std(X(:, i));
end
case 3 %// If we provide three inputs
mean_X = varargin{2}; %// Second input is a mean vector
std_X = varargin{3}; %// Third input is a standard deviation vector
%// Apply the code as seen in the first case
X = varargin{1} - repmat(mean_X, [size(varargin{1}, 1) 1]);
for i = 1:size(X, 2)
X(:, i) = X(:, i) / std_X(:, i);
end
end
如果我可以建议另一种编写此代码的方法,我会使用强大而强大的bsxfun
功能。这避免了必须做任何重复的元素,我们可以在引擎盖下做到这一点。我会重写这个函数,使它看起来像这样:
function [X, mean_X, std_X] = standardize(varargin)
switch nargin
case 1
mean_X = mean(varargin{1}); %// Find mean of each column
std_X = std(varargin{1}); %// Find std. dev. of each column
X = bsxfun(@minus, varargin{1}, mean_X); %// Subtract each column by its respective mean
X = bsxfun(@rdivide, X, std_X); %// Take each column and divide by its respective std dev.
case 3
mean_X = varargin{2};
std_X = varargin{3};
%// Same code as above
X = bsxfun(@minus, varargin{1}, mean_X);
X = bsxfun(@rdivide, X, std_X);
end
我认为上面的新代码比使用for
and快得多repmat
。事实上,众所周知,这bsxfun
比前一种方法更快——尤其是对于更大的矩阵。