Search code examples
matlabfor-loopbsxfun

matlab complex for end loop w/ bsxfun


I have a 2092x252 matrix of doubles and need to create a for loop that uses the bsxfun. Let's just say for this example bsxfun(@minus). What I need the loop to accomplish is to run bsxfun(@minus) using each column as an index. For example, designating column 1 as the index get the difference (using bsxfun(@minus)) with columns 2:252. Then set column 2 as the index and get the difference with columns 3:252 (again using bsxfun(@minus)). The loop has to continue to run until bsxfun(@minus, 251, 252).

The output would be in one variable instead of 251 variables. There would be a total of 31626 data points.

Also, could you please explain the code.


Solution

  • I'm not sure if this is exactly what you wanted, cause it results in 31626x2092 data points, but since you said to take the difference of the columns...

    data=ceil(rand(7,5)*10); % some sample data, works with any matrix(at least 2 columns of course)
    
    N = size(data,2);
    
    %b=cell(N-1,1);
    c=NaN(size(data,1),N*(N-1)/2); % preallocate result matrix
    
    kk=0;
    for ii=1:N-1
        %b{ii} = bsxfun(@minus,data(:,ii),data(:,ii+1:end));
        c(:,kk+(1:N-ii)) = bsxfun(@minus,data(:,ii),data(:,ii+1:end));
        kk=kk+N-ii;
    end
    

    Key here is that in each looping step, you select just the part of the matrix you want to perform the minus operation on, ie: data(:,ii) (= the ii'th column) and data(:,ii+1:end) (= all remaining columns, from the ii'th up to the end of the matrix)

    The bsxfun function description says:
    Apply element-by-element binary operation to two arrays with singleton expansion enabled

    That singleton expansion is what I'm using up here, bsxfun sees the two input being one column and a matrix with same sized columns, and expands the column to be same size as the matrix (=singleton expansion (row dimension gets expanded) )

    So if you want the rows to be subtracted from each other, you can just provide a row and the same matrix as before, and it'll also know what to do, ie expand the row vector along the column dimension:

    N = size(data,1);
    
    %b=cell(N-1,1);
    c=NaN(N*(N-1)/2,size(data,2)); % preallocate result matrix
    
    kk=0;
    for ii=1:N-1
        %b{ii} = bsxfun(@minus,data(ii,:),data(ii+1:end,:));
        c(kk+(1:N-ii),:) = bsxfun(@minus,data(ii,:),data(ii+1:end,:));
        kk=kk+N-ii;
    end
    

    As you can see, the indexing of all the matrices switched places: A(i,j) changed to A(j,i).

    Using cells for the result matrices in each step in the loop would allow easier access to the result, but since you wanted the result in one variable (matrix I assume), I commented those out.

    EDIT

    on preallocating: http://www.mathworks.nl/help/techdoc/matlab_prog/f8-784135.html

    c(:,kk+(1:N-ii));
    kk=kk+N-ii
    

    is the indexing, which was the most tricky:
    When ii=1 you have 251 columns to insert: that'll be column 1->251 in the output variable
    ii=2 -> 250 columns, column 252->501 in the output
    ii=3 -> 249 columns, column 502->750 in the output
    ii=4 => 248 columns, column 751->999 in the output
    etc.

    The kk+(1:N-ii) is essentially doing that: selecting the appropriate columns for the output of bsxfun.
    The variable kk is the number of columns already saved into the output variable c, so obviously it starts at zero. If you change it to another value, say kk_init, the first kk_init columns of c would remain empty and the resulting c matrix will have N*(N-1)/2+kk_init columns instead of N*(N-1)/2.