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

2 visualizaciones (últimos 30 días)
James Akula el 5 de Dic. de 2022
Editada: Jan el 5 de Dic. de 2022
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?
##### 0 comentariosMostrar -2 comentarios más antiguosOcultar -2 comentarios más antiguos

Iniciar sesión para comentar.

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 comentariosMostrar NingunoOcultar Ninguno
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 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 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.)
##### 1 comentarioMostrar -1 comentarios más antiguosOcultar -1 comentarios más antiguos
James Akula el 5 de Dic. de 2022
I knew there had to be one line of code that did this. Thanks!

Iniciar sesión para comentar.

### Categorías

Más información sobre Loops and Conditional Statements en Help Center y File Exchange.

### Community Treasure Hunt

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

Start Hunting!

Translated by