Loren on the Art of MATLAB

Turn ideas into MATLAB

Note

Loren on the Art of MATLAB has been archived and will not be updated.

Comparing repmat and bsxfun Performance

I've been asked repeatedly about the performance comparison between two MATLAB functions, bsxfun and repmat. These two functions can each help with calculations in which two arrays are expected to have the same dimensions, but some of the input dimensions, instead of agreeing, may have the value 1. The simple example I use here is subtracting the columns means from a matrix.

Contents

Setup

First I set up the data.

m = 1e5;
n = 100;
A = rand(m,n);

Code I'm Tempted to Write

And now here's the code I'm tempted to write, safely tucked inside the confines of a try statement.

try
    AZeroMean = A - mean(A);
catch ME
    disp(ME.message);
end
Matrix dimensions must agree.

As you can see, MATLAB does not allow binary operators to work on arrays with different sizes (except when one of the inputs is a scalar value). There are at least two ways to remedy this.

  • Store the intermediate calculation from mean(A) in a vector and then create a new array the same size as A with replicates of the row vector from the mean. You can do this with repmat or via indexing an appropriate number of times into the row of this vector.
  • Call bsxfun with the appropriate two inputs and allow it to perform the equivalent singleton dimension expansion. The nice thing about this is there is no need for a large intermediate array the same size as A. A possible downside, especially since bsxfun is relatively new, is that the code doesn't, at first reading, appear as obvious.
  • Timing repmat

    Using the most excellent timeit utility that Steve Eddins posted to the file exchange, I now time the repmat calculations. First I create an anonymous function that does my calculation. Then I pass that function handle to timeit. timeit carefully warms up the function by running it enough so the times are not subject to first-time effects, figuring out how many times to run it to get meaningful results, and more.

    frepmat = @() A - repmat(mean(A),size(A,1),1);
    timeit(frepmat)
    ans =
          0.30964
    

    Indexing with ones

    repmat uses a variety of techniques for replicating an array, depending on the details of what's being replicated. One technique is to index into the array with ones in the dimension to replicate. Here's an illustative example with a vector.

    q = [17 pi 42 exp(1)];
    q5 = repmat(q,5,1)
    q5 =
               17       3.1416           42       2.7183
               17       3.1416           42       2.7183
               17       3.1416           42       2.7183
               17       3.1416           42       2.7183
               17       3.1416           42       2.7183
    

    Timing Indexing

    One thing I notice with the repmat solution is that I need to create the vector mean(A) for the function. I need to do the same thing without repmat and I want to be able to set up one function call for performing the calculation so I can use timeit. Since I can't index into the results of a function without assigning the output to a variable, I create an intermediate function meanones to help.

    type meanones
    function y = meanones(A)
    
    mn = mean(A);
    y = A - mn(ones(1,size(A,1)),:);
    
    

    Now I'm ready to do the timing.

    findex = @() meanones(A);
    timeit(findex)
    ans =
          0.31389
    

    Timing bsxfun

    Next see the timing calculation done using bsxfun.

    fbsxfun = @() bsxfun(@minus,A,mean(A));
    timeit(fbsxfun)
    ans =
          0.20569
    

    Punchline

    In this example, bsxfun performs fastest. Now that you see bsxfun in action, can you think of uses for this function in your work? Let me know here.




    Published with MATLAB® 7.6


    • print