Ariyan
Ariyan

Reputation: 15168

Fast technique for normalizing a matrix in MATLAB

I want to normalise each column of a matrix in Matlab. I have tried two implementations:

Option A:

mx=max(x);
mn=min(x);
mmd=mx-mn;
for i=1:size(x,1)
    xn(i,:)=((x(i,:)-mn+(mmd==0))./(mmd+(mmd==0)*2))*2-1; 
end

Option B:

mn=mean(x);
sdx=std(x);
for i=1:size(x,1)
    xn(i,:)=(x(i,:)-mn)./(sdx+(sdx==0));
end

However, these options take too much time for my data, e.g. 3-4 seconds on a 5000x53 matrix. Thus, is there any better solution?

Upvotes: 11

Views: 48765

Answers (7)

eykanal
eykanal

Reputation: 27077

Remember, in MATLAB, vectorizing = speed.

If A is an M x N matrix,

A = rand(m,n);
minA = repmat(min(A), [size(A, 1), 1]);
normA = max(A) - min(A);               % this is a vector
normA = repmat(normA, [length(normA) 1]);  % this makes it a matrix
                                       % of the same size as A
normalizedA = (A - minA)./normA;  % your normalized matrix

Upvotes: 8

Francisco
Francisco

Reputation: 31

Note: This code works in Octave and MATLAB versions R2016b or higher.

function X_norm = normalizeMatrix(X)      
      mu = mean(X); %mean    
      sigma = std(X); %standard deviation   
      X_norm = (X - mu)./sigma;    
end

Upvotes: 3

Rishi Dua
Rishi Dua

Reputation: 2334

Let X be a m x n matrix and you want to normalize column wise.

The following matlab code does it

XMean = repmat(mean(X),m,1);
XStd = repmat(std(X),m,1);
X_norm = (X - XMean)./(XStd);

The element wise ./ operator is explained here: http://www.mathworks.in/help/matlab/ref/arithmeticoperators.html

Note: As op mentioned, this is simply a faster solution and performs the same task as looping through the matrix. The underlying implementation of this inbuilt function makes it work faster

Upvotes: 4

user3103059
user3103059

Reputation:

How about using

normc(X)

that would normalize the matrix X columnwise. You need to include the Neural Network Toolbox in your install though.

Upvotes: 1

Adam Binch
Adam Binch

Reputation: 1

How about this?

A = [7, 2, 6; 3, 8, 4]; % a 2x3 matrix

Asum = sum(A); % sum the columns

Anorm = A./Asum(ones(size(A, 1), 1), :); % normalise the columns

Upvotes: -3

tashuhka
tashuhka

Reputation: 5126

Note: I am not providing a freshly new answer, but I am comparing the proposed answers.

Option A: Using bsxfun()

function xn = normalizeBsxfun(x)

    mn = mean(x);
    sd = std(x);
    sd(sd==0) = eps;

    xn = bsxfun(@minus,x,mn);
    xn = bsxfun(@rdivide,xn,sd);

end

Option B: Using a for-loop

function xn = normalizeLoop(x)

    xn = zeros(size(x));

    for ii=1:size(x,2)
        xaux = x(:,ii);
        xn(:,ii) = (xaux - mean(xaux))./mean(xaux);
    end

end

We compare both implementations for different matrix sizes:

expList = 2:0.5:5;
for ii=1:numel(expList)
    expNum = round(10^expList(ii));
    x = rand(expNum,expNum); 
    tic;
    xn = normalizeBsxfun(x);
    ts(ii) = toc; 
    tic;
    xn = normalizeLoop(x);
    tl(ii) = toc; 
end

figure;
hold on;
plot(round(10.^expList),ts,'b');
plot(round(10.^expList),tl,'r');
legend('bsxfun','loop');
set(gca,'YScale','log') 

The results show that for small matrices, the bsxfun is faster. But, the difference is neglect able for higher dimensions, as it was also found in other post.

enter image description here

The x-axis is the squared root number of matrix elements, while the y-axis is the computation time in seconds.

Upvotes: 3

Jonas
Jonas

Reputation: 74940

Use bsxfun instead of the loop. This may be a bit faster; however, it may also use more memory (which may be an issue in your case; if you're paging, everything'll be really slow).

To normalize with mean and std, you'd write

mn = mean(x);
sd = std(x);
sd(sd==0) = 1;

xn = bsxfun(@minus,x,mn);
xn = bsxfun(@rdivide,xn,sd);

Upvotes: 15

Related Questions