这段用于标准化数据的代码是如何工作的?

How does this code for standardizing data work?

我为机器学习课程提供了一个 standardize 函数,该函数没有很好的记录,而且我还是 MATLAB 的新手,所以我只是想分解这个函数。任何语法解释或标准化的一般想法都会有很大帮助。我们使用此函数对大型矩阵中提供的一组训练数据进行标准化。分解代码片段的大部分行会对我有很大帮助。太感谢了。

function [X, mean_X, std_X] = standardize(varargin)
switch nargin
    case 1
        mean_X = mean(varargin{1});
        std_X = std(varargin{1});

        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     
    case 3
        mean_X = varargin{2};
        std_X = varargin{3};
        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

此代码接受大小为 M x N 的数据矩阵,其中 M 是该矩阵中一个数据样本的维数,N 是样本总数。因此,这个矩阵的一列是一个数据样本。数据样本都是水平堆叠的,都是列的。

现在,此代码的真正目的是获取矩阵的所有列并对数据进行标准化/规范化,以便每个数据样本显示zero mean and unit variance .这意味着在这个转换之后,如果你找到这个矩阵中任何一列的平均值,它会是 0,方差会是 1。这是统计分析、机器学习和计算机视觉中标准化值的一种非常标准的方法.

这个其实来自统计分析中的z-score。具体来说,归一化方程为:

给定一组数据点,我们用这些数据点的平均值减去相关值,然后除以各自的标准差。您如何调用此代码如下。给定这个我们称之为 X 的矩阵,您可以通过两种方式调用此代码:

  • 方法一:[X, mean_X, std_X] = standardize(X);
  • 方法#2:[X, mean_X, std_X] = standardize(X, mu, sigma);

第一种方法自动推断出X每列的均值和X每列的标准差。 mean_Xstd_X 都是 return 1 x N 向量,它们为您提供矩阵 X 中每一列的均值和标准差。第二种方法允许您为 X 的每一列手动指定平均值 (mu) 和标准偏差 (sigma)。这可能用于调试,但在这种情况下,您可以将 musigma 指定为 1 x N 向量。 mean_Xstd_X 的 return 与 musigma 相同。

恕我直言,代码写得有点糟糕,因为你当然可以实现这种矢量化,但代码的要点是它找到矩阵的每一列的平均值 X 如果我们正在使用方法#1,复制这个向量,使其成为 M x N 矩阵,然后我们用 X 减去这个矩阵。这将减去每一列各自的平均值。我们还在均值减法之前计算每列的标准差。

一旦我们这样做了,我们就会通过将每一列除以其各自的标准差来标准化我们的 X。顺便说一句,做 std_X(:, i) 是多余的,因为 std_X 已经是一个 1 x N 向量。 std_X(:, i) 表示获取第 ith 列的所有行。如果我们已经有了一个 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

我认为上面的新代码比使用 forrepmat 快得多。事实上,众所周知 bsxfun 比前一种方法更快 - 特别是对于较大的矩阵。