average over a certain range of index ?

96 visualizaciones (últimos 30 días)
Megha
Megha el 14 de Feb. de 2021
Editada: Jan el 15 de Feb. de 2021
I have vector A = [1 7 12 20 23 31]; and B = [6 11 19 22 30 35].
now i want to average another matrix C with 1x35 elements over the index range "1:6, 7:11, 12:19, 20:22, 23:30, 30:35".
is it possible to do something like mean(C(A:B))?? However this does not work. Can anyone please help in this regard.?
  1 comentario
Jan
Jan el 14 de Feb. de 2021
Editada: Jan el 14 de Feb. de 2021
How large are the inputs? Can the intervals overlap? Is A(2:end) and B(1:end-1)+1 equal in every case?

Iniciar sesión para comentar.

Respuestas (4)

randerss simil
randerss simil el 14 de Feb. de 2021
clear
clc
A = [1 7 12 20 23 31];
B = [6 11 19 22 30 35];
C = rand(1,35)
for i = 1:numel(A)
kk(i) = mean(C(A(i):B(i)));
end
  1 comentario
Megha
Megha el 14 de Feb. de 2021
randerss simil thank you so much for your reply.
Unfortunately, this is my last option... I know this stuff... but i wanted to do it quickly without using FOR loop...

Iniciar sesión para comentar.


Jan
Jan el 14 de Feb. de 2021
Editada: Jan el 14 de Feb. de 2021
nC = 1e6; % Number of elements of C
nA = 1e5; % Number of intervals
C = rand(1, nC); % Test data
% Create indices: ----------------------
% non-overlapping intervals with gaps
% v = sort(randperm(nC, nA * 2));
% A = v(1:2:end);
% B = v(2:2:end);
% overlapping:
v = sort(randi([1, nC], nA, 2), 2);
A = v(:, 1);
B = min(v(:, 2), A + 100); % Maximum width: 101
% non-overlapping without gaps:
% B = [sort(randperm(1e6-1, 1e5-1)), 1e6];
% A = [1, B(1:end-1) + 1];
tic;
for i = 1:numel(A)
kk1(i) = mean(C(A(i):B(i)));
end
toc
tic;
kk2 = zeros(1, numel(A));
for i = 1:numel(A)
kk2(i) = mean(C(A(i):B(i)));
end
toc
tic;
kk3 = zeros(1, numel(A));
for i = 1:numel(A)
kk3(i) = sum(C(A(i):B(i))) / (B(i)-A(i)+1);
end
toc
isequal(kk1, kk2, kk3) % Yes, the outputs are identical
The timings:
% Elapsed time is 0.211296 seconds. No pre-allocation
% Elapsed time is 0.185444 seconds. With pre-allocation
% Elapsed time is 0.014207 seconds. SUM/Len instead of MEAN
This shows, that mean() is the bottleneck of the standard approach.
[EDITED] I'm working on a C-Mex version, which is 10 times faster. I'm going to publish it in the FEX.

Image Analyst
Image Analyst el 14 de Feb. de 2021
Megha, here is a non-for loop way of doing it using splitapply():
A = [1 7 12 20 23 31];
B = [6 11 19 22 30 35];
C = rand(1,35)
% Method 1 : using splitapply() and no for loop:
% Create group labels.
r = repelem(1:length(A), B - A + 1)
% Get the mean of each group.
theMeans = splitapply(@mean, C, r)
% Method 2 : for loop.
% Double check first method by comparing to the for loop method:
for i = 1:numel(A)
kk(i) = mean(C(A(i):B(i)));
end
kk % Report to command window. The values are the same, as expected.
  1 comentario
Jan
Jan el 14 de Feb. de 2021
Editada: Jan el 15 de Feb. de 2021
splitapply calls accumarry internally. Then this is a shortcut:
m = accumarray(r.', C, [], @mean);
Calling the function handle @mean is surpringly slower than SUM/Len. Some timings:
% Dense and not overlapping intervals:
C = rand(1, 1e6);
B = [sort(randperm(1e6-1, 1e5-1)), 1e6];
A = [1, B(1:end-1) + 1];
tic;
r = repelem(1:length(A), B - A + 1);
m1 = splitapply(@mean, C, r);
toc
tic;
r = repelem(1:length(A), B - A + 1);
m2 = accumarray(r.', C, [], @mean);
toc
tic; % Implicit @sum and specify the output size:
r = repelem(1:length(A), B - A + 1);
m3 = accumarray(r.', C, [numel(A), 1]) ./ (B(:) - A(:) + 1);
toc
isequal(m1(:), m2, m3) % true
% R2018b, Win10, Intel i7
% Elapsed time is 2.463368 seconds. SPLITAPPLY
% Elapsed time is 0.927217 seconds. ACCUMARRAY(@mean)
% Elapsed time is 0.009275 seconds. ACCUMARRAY(sum) ./ Len
Factor 265 faster than splitapply and factor 100 compared to @mean.

Iniciar sesión para comentar.


Jan
Jan el 14 de Feb. de 2021
Editada: Jan el 14 de Feb. de 2021
Another method assuming, that the intervals are dense and not overlapping:
A = [1 7 12 20 23 31];
B = [6 11 19 22 30 35]; % A(2:end) == B(1:end-1) + 1 !!!
C = rand(1,35)
S = cumsum(C);
SB = S(B);
kk = [SB(1), diff(SB)] ./ (B - A + 1)
This is less accurate for large C, because cumsum accumulates rounding errors.
Timings:
C = rand(1, 1e6);
% Dense and not overlapping intervals:
B = [sort(randperm(1e6-1, 1e5-1)), 1e6];
A = [1, B(1:end-1) + 1];
tic;
kk3 = zeros(1, numel(A));
for i = 1:numel(A)
kk1(i) = sum(C(A(i):B(i))) / (B(i)-A(i)+1);
end
toc
tic
S = cumsum(C);
SB = S(B);
kk2 = [SB(1), diff(SB)] ./ (B - A + 1);
toc
max(abs(kk1 - kk2)) % 2.91e-11 !!! Is this sufficient?!
Timings:
% Elapsed time is 0.040201 seconds. Loop SUM/Len
% Elapsed time is 0.004538 seconds. CUMSUM (rounding limitations!)
% Elapsed time is 0.009275 seconds. ACCUMARRAY SUM/Len
% Elapsed time is 0.002097 seconds. C-Mex (published soon)

Categorías

Más información sobre Preprocessing Data 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