average over a certain range of index ?

92 Ansichten (letzte 30 Tage)
Megha
Megha am 14 Feb. 2021
Bearbeitet: Jan am 15 Feb. 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 Kommentar
Jan
Jan am 14 Feb. 2021
Bearbeitet: Jan am 14 Feb. 2021
How large are the inputs? Can the intervals overlap? Is A(2:end) and B(1:end-1)+1 equal in every case?

Melden Sie sich an, um zu kommentieren.

Antworten (4)

randerss simil
randerss simil am 14 Feb. 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 Kommentar
Megha
Megha am 14 Feb. 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...

Melden Sie sich an, um zu kommentieren.


Jan
Jan am 14 Feb. 2021
Bearbeitet: Jan am 14 Feb. 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 am 14 Feb. 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 Kommentar
Jan
Jan am 14 Feb. 2021
Bearbeitet: Jan am 15 Feb. 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.

Melden Sie sich an, um zu kommentieren.


Jan
Jan am 14 Feb. 2021
Bearbeitet: Jan am 14 Feb. 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)

Kategorien

Mehr zu Preprocessing Data finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by