Can the efficienty of this code be improved, either computationally or just in terms of lines of code?

4 visualizaciones (últimos 30 días)
Dumb question for a smart person who has a moment to kill.
Let's say I have data that will come in from n groups, and I know a priori those groups will be numbered 1 through n in some variable, A. I will have a second variable, B, that contains the data. Then, I want to get (for example) the mean of the data in each group. It is easy to pull off with a loop, but is there better code I could be using for this procedure? For a small example dataset, I might have
A = [2; 3; 1; 2; 2; 3; 1; 2; 2; 3];
B = [4.10047; 7.44549; 3.62159; 6.56964; 2.87221; 4.51231; 4.01697; 5.60534; 5.5440; 7.07802];
tic
%%% Can this be done better or in one line of code? %%%
C = NaN(max(A), 1);
for ii = 1:numel(C)
C(ii) = mean(B(A == ii));
end
%%% Can this be done better or in one line of code? %%%
toc
Elapsed time is 0.004956 seconds.
disp(C)
3.8193 4.9383 6.3453
bar(C)
Is there a better way to do this?

Respuesta aceptada

Jan
Jan el 5 de Dic. de 2022
Editada: Jan el 5 de Dic. de 2022
A0 = [2; 3; 1; 2; 2; 3; 1; 2; 2; 3];
B0 = [4.10047; 7.44549; 3.62159; 6.56964; 2.87221; 4.51231; 4.01697; 5.60534; 5.5440; 7.07802];
A = repmat(A0, 1e6, 1); % Let Matlab work with more than tiny data
B = repmat(B0, 1e6, 1);
tic
C = NaN(max(A), 1);
for ii = 1:numel(C)
m = A == ii;
C(ii) = sum(B(A == ii));
end
toc
Elapsed time is 0.132737 seconds.
Shorter but slower:
tic
D = accumarray(A, B, [], @mean);
toc
Elapsed time is 0.775913 seconds.
isequal(C, D)
ans = logical
1
Another apporach:
tic
S = zeros(max(A), 1);
N = zeros(size(S));
for k = 1:numel(A)
m = A(k);
S(m) = S(m) + B(k);
N(m) = N(m) + 1;
end
E = S ./ N;
toc
Elapsed time is 0.091502 seconds.
isequal(C, E) % Not equal!!!
ans = logical
0
% But the differences are caused by rounding only:
(C - E) ./ C
ans = 3×1
1.0e-10 * -0.0674 0.2422 -0.1365
The difference is caused by the numerical instability of sums. Comparing the results with the mean of A0 and B0 shows, that all methods have comparable accuracy.
Locally under R2018b I get these timings:
Elapsed time is 0.205890 seconds. % Original
Elapsed time is 0.512173 seconds. % ACCUMARRAY
Elapsed time is 0.061097 seconds. % Loop over inputs
  2 comentarios
James Akula
James Akula el 5 de Dic. de 2022
Editada: Torsten el 5 de Dic. de 2022
Thanks. Looks like there are multiple ways to trim the code, but no way to do it faster.
I took your repmat modification and added Steven Lord's answer, below, and the original loop looks like the clear winner.
A = [2; 3; 1; 2; 2; 3; 1; 2; 2; 3];
B = [4.10047; 7.44549; 3.62159; 6.56964; 2.87221; 4.51231; 4.01697; 5.60534; 5.5440; 7.07802];
A = repmat(A, 1e6, 1); % Let Matlab work with more than tiny data
B = repmat(B, 1e6, 1);
tic
C = NaN(max(A), 1);
for ii = 1:numel(C)
C(ii) = mean(B(A == ii));
end
toc
Elapsed time is 0.157308 seconds.
tic
D = accumarray(A, B, [], @mean);
toc
Elapsed time is 0.873463 seconds.
tic
[E] = groupsummary(B, A, @mean)
E = 3×1
3.8193 4.9383 6.3453
toc
Elapsed time is 2.450524 seconds.
tic
F = arrayfun(@(i)mean(B(A == i)),1:max(A)).';
toc
Elapsed time is 0.156121 seconds.
isequal(C, D, E, F)
ans = logical
1
Torsten
Torsten el 5 de Dic. de 2022
I took your repmat modification and added Steven Lord's answer, below, and the original loop looks like the clear winner.
Or "arrayfun" (see above).

Iniciar sesión para comentar.

Más respuestas (1)

Steven Lord
Steven Lord el 5 de Dic. de 2022
A = [2; 4; 1; 2; 2; 4; 1; 2; 2; 4];
B = [4.10047; 7.44549; 3.62159; 6.56964; 2.87221; 4.51231; 4.01697; 5.60534; 5.5440; 7.07802];
[C, groupnumbers] = groupsummary(B, A, @mean)
C = 3×1
3.8193 4.9383 6.3453
groupnumbers = 3×1
1 2 4
The groupnumbers output can help if some elements in 1:n don't appear in A (as is the case using the modified A I used in this example where all the 3's are replaced by 4's.)

Categorías

Más información sobre Matrix Indexing en Help Center y File Exchange.

Etiquetas

Productos

Community Treasure Hunt

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

Start Hunting!

Translated by