Keith D
Keith D

Reputation: 413

Vectorization of 2 for loops in MATLAB

I have just started exploring world of vectorization. I got the 1-D vectorization down but i am having trouble vectorizing the following code. I want to do away with at least one of the for loops if possible b/c I plan to use this on a much larger data set over many iterations so saving computation time is of the essence.

CityPairs = [7 3
3 1
3 1
1 7
7 1
3 4
5 1
4 6];
Offices = [1;3;7];
nOffices = size(Offices,1);

connection = zeros(nOffices);
for i = 1:nOffices
    for j = 1:nOffices
        connection(i,j) = sum(Offices(i) == CityPairs(:,1)...
            & CityPairs(:,2) == Offices(j));
    end
end   
disp(connection)

In this example there are 7 cities, three of which have offices. I want a pairwise matrix for the cities with offices to capture the sum of all the one way connections between each. The answer for above problem should be:

 0     0     1
 2     0     0
 1     1     0

Any suggestions are welcome. Thanks in advance.

Keith

Upvotes: 1

Views: 188

Answers (3)

Eitan T
Eitan T

Reputation: 32930

Here's an alternative solution with sparse:

dims = max(max(CityPairs), max(Offices));
A = sparse(CityPairs(:, 1), CityPairs(:, 2), 1, dims(1), dims(2));
result = full(A(Offices, Offices));

This should speed up your computation a bit1 when compared to the suggested bsxfun solution.


1 Runs 5 times faster on MATLAB 2012a (Windows Server 2008 R2 running on a 2.27GHz 16-core Intel Xeon processor)

Upvotes: 2

Keith D
Keith D

Reputation: 413

Answer provided by Cedric Wannaz on MathWorks Forum

It is not trivial to "vectorize" this setup, as there are operations that require some look up table, and there is accumulation (unless you find a trick). This is likely to make the approach without FOR loops more complicated (code-wise) than the basic, loop-based approach. So let's start with the trick first ;-) ..

 A = double( bsxfun(@eq, CityPairs(:,1), Offices.') ) ;
 B = double( bsxfun(@eq, CityPairs(:,2), Offices.') ) ;
 A.' * B

Alternate approach: http://www.mathworks.com/matlabcentral/answers/91294-vectorization-of-2-for-loops-in-matlab

Upvotes: 0

Oleg
Oleg

Reputation: 10676

Your task is some selective cross-tabulation. You can accomplish this easily by accumulating counts to the positions of interest, indexed by your Offices:

% Row and col subs
[~,rsubs] = ismember(CityPairs(:,1),Offices);
[~,csubs] = ismember(CityPairs(:,2),Offices);

% Select where both belong to Offices, i.e. non 0
subs = [rsubs,csubs];
subs = subs(all(subs,2),:);

% Accumulate
accumarray(subs,1)

The result

ans =
     0     0     1
     2     0     0
     1     1     0

If you have the Statistics Toolbox, you could use crosstab directly, but then you would need to select the rows and columns of interest:

crosstab(CityPairs(:,1),CityPairs(:,2))
ans =
     0     0     0     0     1
     2     0     1     0     0
     0     0     0     1     0
     1     0     0     0     0
     1     1     0     0     0

Upvotes: 2

Related Questions