1

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
4

1 回答 1

2

此代码接受大小为 的数据矩阵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 的标准差Xmean_X并且std_X都将返回1 x N向量,为您提供矩阵中每一列的均值和标准差X。第二种方法允许您为 的每一列手动指定平均值 ( mu) 和标准差 ( ) 。这可能用于调试,但在这种情况下,您可以同时指定和作为向量。返回的和与和相同。sigmaXmusigma1 x Nmean_Xstd_Xmusigma

恕我直言,代码写得有点糟糕,因为你当然可以实现这个向量化,但代码的要点是,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

我认为上面的新代码比使用forand快得多repmat。事实上,众所周知,这bsxfun比前一种方法更快——尤其是对于更大的矩阵。

于 2015-02-24T07:39:15.083 回答