Optimise/replace this for loop used in calculation of mutual information
1 vue (au cours des 30 derniers jours)
Afficher commentaires plus anciens
So I previously posted on here with regards to some code given HERE. Thanks to the help of Jan Simons I have managed to eliminate one of the nested for loops to speed up the code pretty significantly. However, due to the dimensionality of the project and future projects I am working on I still need to optimise the code. I ran the profiler and the following block of code seems to be bottleneck:
Eps = zeros(nObs, 1);
Nn = zeros(nObs, 1);
nx1 = zeros(nObs, 1);
ny1 = zeros(nObs, 1);
nx2 = zeros(nObs, 1);
ny2 = zeros(nObs, 1);
for i = 1:nObs
dxSample = dx(i, :);
dxSample(i) = [];
dySample = dy(i, :);
dySample(i) = [];
dzSample = dz(i, :);
dzSample(i) = [];
[EpsSample, NnSample] = sort(dzSample, 'ascend');
Eps(i) = EpsSample(k);
Nn(i) = NnSample(k);
nx1(i) = sum(dxSample < Eps(i));
ny1(i) = sum(dySample < Eps(i));
nx2(i) = sum(dxSample <= Eps(i));
ny2(i) = sum(dySample <= Eps(i));
end
Note that the k is typically quite low: between 3-10, nObs is around 4364. Is there any way of speeding this up? Maybe even eliminating the for loop altogether if possible? Any help is very much appreciated!
5 commentaires
Walter Roberson
le 16 Jan 2018
I have seen several reports that implicit expansion is often slower than bsxfun. The details are likely to vary with release.
Réponse acceptée
Greg
le 16 Jan 2018
Modifié(e) : Greg
le 18 Jan 2018
Taking some guesses:
eyeinds = eye(nObs,'logical');
dx2(eyeinds) = Inf;
dy2(eyeinds) = Inf;
dz2(eyeinds) = Inf;
% Edit to incorporate Jan's suggestions:
[EpsSample2, NnSample2] = mink(dz2,k,2);
Eps2 = EpsSample2(:,end);
Nn2 = NnSample2(:,end);
% [EpsSample2, NnSample2] = sort(dz2,2,'ascend');
% Eps2 = EpsSample2(:,k);
% Nn2 = NnSample2(:,k);
nx12 = sum(dx2 < Eps2,2);
ny12 = sum(dy2 < Eps2,2);
nx22 = sum(dx2 <= Eps2,2);
ny22 = sum(dy2 <= Eps2,2);
8 commentaires
Plus de réponses (1)
Jan
le 16 Jan 2018
Sorting the complete array is a waste of time if all you need is the k.th smallest element. Under Matlab 2017b see mink to solve this much faster.
A further idea: Omit setting the diagonal to Inf, but leave it at zero. Then the result of nx12 etc. is 1 to large.
[Eps2, Nn2] = mink(dz2, 2, k);
nx12 = sum(dx2 < Eps2, 2) - 1;
ny12 = sum(dy2 < Eps2, 2) - 1;
nx22 = sum(dx2 <= Eps2, 2) - 1;
ny22 = sum(dy2 <= Eps2, 2) - 1;
2 commentaires
Greg
le 16 Jan 2018
Modifié(e) : Greg
le 17 Jan 2018
Leaving at zero only works if all data is guaranteed positive. And that throws off the min counting in dz. I didn't want to make that assumption.
Just noticed your version leaves Eps2 as a non-vector for k > 1. I've edited my answer to incorporate the awesome suggestion to use mink.
Voir également
Catégories
En savoir plus sur Reference Applications dans Help Center et File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!