Cellfun versus Simple Matlab Loop performance

后端 未结 4 1581
挽巷
挽巷 2020-11-27 19:41

When I started working with matlab sometime ago in the university, my supervisor would kill me if he saw any unnecessary for loop (he would ask for exchanging it for k

相关标签:
4条回答
  • 2020-11-27 20:18

    I will add one answer with the results that I tested myself, but I would be glad if people contribute with their knowledge, this is just a simple test I've made.

    I've tested the following conditions with cell size of 1000 and 1000 loops (results on total time, and I would probably have to run more than 1000 times, because I am having a little fluctuation on the results, but anyway, this is not a scientific article):

    • Basic operation (sum)
      • Simple for loop: 0.2663 s
      • cellfun: 9.4612 s
    • String Operation (strcmp)
      • Simple for loop: 1.3124 s
      • cellfun: 11.8099 s
    • Built-in (isempty)
      • Simple for loop: 8.9042 s
      • cellfun (string input -> see this reference): 0.0105 s
      • cellfun (fcn handle input -> see this reference): 0.9209 s
    • Non-uniform (regexp)
      • Simple for loop: 24.2157 s
      • cellfun (string input): 44.0424 s

    So, it seems that cellfun with anonymous function calls are slower than a simple for loop, but if you will use a builtin matlab method, do it with cellfun and use it with the string quotation. This is not necessarily true for all cases, but at least for the tested functions.

    The implemented test code (I am far from being an optimization specialist, so here is the code in case I did something wrong):

    function ...
      [loop_timeAdd,cellfun_timeAdd,...
      loop_timeStr,cellfun_timeStr,...
      loop_timeBuiltIn,cellfun_timeBuiltInStrInput,...
      cellfun_timeBuiltyInFcnHandle,...
      loop_timeNonUniform,cellfun_timeNonUniform] ...
      = test_cellfun(nTimes,nCells)
    
    myCell = repmat({0},1,nCells);
    output = zeros(1,nCells);
    
    % Basic operation
    tic;
    for k=1:nTimes
      for m=1:nCells
        output(m) = myCell{m} + 1;
      end
    end
    loop_timeAdd=toc;
    
    tic;
    for k=1:nTimes
      output = cellfun(@(in) in+1,myCell);
    end
    cellfun_timeAdd=toc;
    
    % String operation
    myCell = repmat({'matchStr'},1,nCells); % Add str that matches
    myCell(1:2:end) = {'dontMatchStr'}; % Add another str that doesnt match
    output = zeros(1,nCells);
    
    tic;
    for k=1:nTimes
      for m=1:nCells
        output(m) = strcmp(myCell{m},'matchStr');
      end
    end
    loop_timeStr=toc;
    
    tic;
    for k=1:nTimes
      output = cellfun(@(in) strcmp(in,'matchStr'),myCell);
    end
    cellfun_timeStr=toc;
    
    % Builtin function (isempty)
    myCell = cell(1,nCells); % Empty
    myCell(1:2:end) = {0}; % not empty
    output = zeros(1,nCells);
    
    tic;
    for k=1:nTimes
      for m=1:nCells
        output(m) = isempty(myCell{m});
      end
    end
    loop_timeBuiltIn=toc;
    
    tic;
    for k=1:nTimes
      output = cellfun(@isempty,myCell);
    end
    cellfun_timeBuiltyInFcnHandle=toc;
    
    tic;
    for k=1:nTimes
      output = cellfun('isempty',myCell);
    end
    cellfun_timeBuiltInStrInput=toc;
    
    % Builtin function (isempty)
    myCell = repmat({'John'},1,nCells);
    myCell(1:2:end) = {'Doe'};
    output = cell(1,nCells);
    
    tic;
    for k=1:nTimes
      for m=1:nCells
        output{m} = regexp(myCell{m},'John','match');
      end
    end
    loop_timeNonUniform=toc;
    
    tic;
    for k=1:nTimes
      output = cellfun(@(in) regexp(in,'John','match'),myCell,...
        'UniformOutput',false);
    end
    cellfun_timeNonUniform=toc;
    
    0 讨论(0)
  • 2020-11-27 20:20

    If performance is a major factor you should avoid using cells, loops or cellfun/arrayfun. It's usually much quicker to use a vector operation (assuming this is possible).

    The code below expands on Werner's add example with standard array loop and array operations.

    The results are:

    • Cell Loop Time - 0.1679
    • Cellfun Time - 2.9973
    • Loop Array Time - 0.0465
    • Array Time - 0.0019

    Code:

    nTimes = 1000;
    nValues = 1000;
    myCell = repmat({0},1,nValues);
    output = zeros(1,nValues);
    
    % Basic operation
    tic;
    for k=1:nTimes
      for m=1:nValues
        output(m) = myCell{m} + 1;
      end
    end
    cell_loop_timeAdd=toc;    
    fprintf(1,'Cell Loop Time %0.4f\n', cell_loop_timeAdd);
    
    tic;        
    for k=1:nTimes
      output = cellfun(@(in) in+1,myCell);
    end
    cellfun_timeAdd=toc;
    fprintf(1,'Cellfun Time %0.4f\n', cellfun_timeAdd);
    
    
    myData = repmat(0,1,nValues);
    tic;
    for k=1:nTimes
      for m=1:nValues
        output(m) = myData(m) + 1;
      end
    end
    loop_timeAdd=toc;
    fprintf(1,'Loop Array Time %0.4f\n', loop_timeAdd);
    
    tic;
    for k=1:nTimes
        output = myData + 1;
    end
    array_timeAdd=toc;
    fprintf(1,'Array Time %0.4f\n', array_timeAdd);
    
    0 讨论(0)
  • 2020-11-27 20:27
    clear all;
    ntimes = 1000;
    
    r = 100;
    c = 100;
    d = 100;
    A = rand(r, c, d);
    B = rand(r, c, d);
    
    tic
    for i = 1:ntimes
        for j = 1 : d
            result = A(:, :, j) * B(:, :, j);
        end
    end
    toc
    
    A_cell = num2cell(A, [1 2]);
    B_cell = num2cell(B, [1 2]);
    tic
    for i = 1 : ntimes
        result2 = cellfun(@(x, y) x*y, A_cell, B_cell, 'uni', 0);
    end
    toc
    

    Try this maybe. Test it for few more times. On average, cellfun is faster than the double loop.

    0 讨论(0)
  • 2020-11-27 20:34

    Here is how I would typically decide on which solution to use:

    1. Can I do it with straightforward matrix operations? Do it, it will be the fastest you can get and typically more readable.
    2. Am I doing something simple? Go to 3, otherwise go to 4.
    3. Can I do it with bsxfun? Do it, it will be very fast and hopefully readable.
    4. Otherwise use a simple for loop

    As you may note, I pretty much never use cellfun for performance. This is due to the following logic:

    1. Cellfun does not perform much faster than a loop usually, and is mostly good for dealing with cells.
    2. If performance is important, you probably want to avoid cells alltogether, and as such you won't need cellfun.
    0 讨论(0)
提交回复
热议问题