toka15
toka15

Reputation: 49

Select several ranges of a column according to their value and insert the mean value of the second column into a new matrix in Matlab

I have a matrix:

V1 V2
1 12
1 12
0 23
0 24
1 45
1 67

I want to calculate the mean of the successive values of V2 only as long as V1 is >0 and insert the results into a new matrix. I want to do this for all values of V1. In this example I would get:

12
56

Any idea how I can do this in Matlab? Thank you.

Upvotes: 1

Views: 52

Answers (2)

Sardar Usama
Sardar Usama

Reputation: 19689

Using the idea of manipulating V1 and creating subs from rahnema1's answer, here is an alternative way of using accumarray:

V1 = V1 > 0;
subs = cumsum(diff([false;V1]) == 1);
result = accumarray (subs(V1), V2(V1), [], @mean);

Benchmark:
Here is a comparison of the two answers:

V1 = repmat(V1,1e6,1);   
V2 = repmat(V2,1e6,1);    
V1 = V1 > 0;
subs = cumsum(diff([false;V1]) == 1);

disp(['rahnema1''s answer = ', num2str(timeit(@() rahnema1(V1,V2,subs)))]);
disp(['Usama''s answer = ', num2str(timeit(@() usama(V1,V2,subs)))]);

function rahnema1(V1,V2,subs)
p = V1 .* V2;
f = find(V1,1);
result = accumarray (subs(f:end), f:numel(V1), [], @(x)sum(p(x))./sum(V1(x)));
end

function usama(V1,V2,subs)
result = accumarray (subs(V1),V2(V1), [], @mean);
end

rahnema1's answer = 4.3385
Usama's answer = 5.6088

rahnema1's code is faster than that of mine.

Upvotes: 2

rahnema1
rahnema1

Reputation: 15867

Here is a solution using cumsum and accumarray:

V1 = V1 > 0;
f = find(V1,1);
subs = cumsum(diff([false;V1]) == 1);
p = V1 .* V2;
result = accumarray (                ...
            subs(f:end),             ...
            f:numel(V1),             ...
            [],                      ...
            @(x)sum(p(x))./sum(V1(x))...
        );

Upvotes: 2

Related Questions