How can I speed up this loop (or avoid using it)?

I am trying to map the average concentration of a chemical (concxy2) at arbitrarily located points (xposn2 zposn2) (all 2D matrices, not monotonic) onto a 2D grid (xedges zedges). There are often several points that end up in a given bin of the grid, and I would like to quickly find the average of these points in a bin. Here's the code I'm presently using:
%Find where points in xposn2 and zposn2 fall in the grids defined by xedges and zedges. The number of points in a given bin is given by N, and the locations of the points in the grid are given by binx and binz.
[N,zedges,xedges,binz,binx]=histcounts2(zposn2,xposn2,NBINS,'YBinLimits',[xmin_bin,xmax_bin],'XBinLimits',[zmin_bin,zmax_bin]);
%Find the rows and columns of the new grid where there are points
[indr,indc]=find(N>0);
%Initialize an array for the binned concentrations
conc_sum = zeros(NBINS(1),NBINS(2));
%Now find out which points are in a given bin, and average their concentrations concxy2 in that bin
for i=1:length(indr)
indpts=find(binx == indc(i) & binz == indr(i));
conc_sum(indr(i),indc(i)) = sum(concxy2(indpts));
clear indpts;
end
The first part of this runs wonderfully quickly. The loop, however, with the matrix size I'm using, is VERY slow, even though I'm only looking for the bin locations of existing points (rather than looping through the entire binx binz arrays). The indices of the row and column locations of the points are indr and indc, respectively.
It is extremely fast to find how many points are in a given bin (N). But I can't figure out a way to quicly find the concentrations associated with those points (concxy2) and average them in the given bin (binx(i), binz(i)).
Any suggestions on speeding up or removing the loop would be MUCH appreciated.
Peter

 Accepted Answer

Guillaume
Guillaume on 13 Mar 2019
Edited: Guillaume on 13 Mar 2019
%your original start, we don't need the first 3 outputs
[~, ~, ~, binz, binx]=histcounts2(zposn2,xposn2,NBINS,'YBinLimits',[xmin_bin,xmax_bin],'XBinLimits',[zmin_bin,zmax_bin]);
conc_sum = accumarray([binx(:), binz(:)], concxy(:), [NBINS, NBINS], @mean) %average according to bin
Note that if zposn2, xposn2 and concxy are already column vectors, you don't need the (:).

1 Comment

Guillaume, dude, you are my new hero! Thank you! After a little fiddling, that worked perfectly! The calculation went from 20 minutes down to 10 seconds!

Sign in to comment.

More Answers (0)

Categories

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!