average over a certain range of index ?

77 vues (au cours des 30 derniers jours)
Megha
Megha le 14 Fév 2021
Modifié(e) : Jan le 15 Fév 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 commentaire
Jan
Jan le 14 Fév 2021
Modifié(e) : Jan le 14 Fév 2021
How large are the inputs? Can the intervals overlap? Is A(2:end) and B(1:end-1)+1 equal in every case?

Connectez-vous pour commenter.

Réponses (4)

randerss simil
randerss simil le 14 Fév 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 commentaire
Megha
Megha le 14 Fév 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...

Connectez-vous pour commenter.


Jan
Jan le 14 Fév 2021
Modifié(e) : Jan le 14 Fév 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 le 14 Fév 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 commentaire
Jan
Jan le 14 Fév 2021
Modifié(e) : Jan le 15 Fév 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.

Connectez-vous pour commenter.


Jan
Jan le 14 Fév 2021
Modifié(e) : Jan le 14 Fév 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)

Catégories

En savoir plus sur Preprocessing Data 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!

Translated by