2016-05-03 1 views
2

У меня есть вектор 21x2 в Matlab который выглядит следующим образом:Для цикла усреднения по времени отдельных точек Matlab

A = [0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5; 
    0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1]'; 

каждый элемент в первой строке соответствует либо 0 или 1 во втором ряду. Я должен относиться к каждому из множества 0's и 1's в виде блоков, так что можно выделить такие элементы, что у меня есть вектор, содержащего все первых элементов 1 блоков, а затем другой вектор, содержащей все вторых элементов блоков 1 и т. д., пока я не выделил все элементы.

так, например, vector1=[1.0 2.1], vector2=[1.1 2.2] и т. Д.

Это потому, что мне нужно усреднять по отдельным точкам между блоками, чтобы у меня было, например. avg_vector1, avg_vector2, avg_vector3 ... и т. д.

До сих пор я пытался написать цикл, чтобы сделать это, но я уже могу сказать, что это будет не так эффективно и может не работать каждый раз, потому что мне придется имеют if для каждого j (см. ниже), а число «j» на самом деле не фиксировано, иногда блок может быть длиннее, иногда он может быть короче.

j=1; 
for i=1:size(A,1) 
if A(i,2)==1 
    if j==1 
     vector1(i)=A(i,1); 
     j=j+1; %j is acting as a counter for the "size" of the block of 0's and 1's 
    if j==2 
     vector2(i)=A(i,1); 
    **incomplete** 

Кто-нибудь знает, как это сделать элегантно и просто?

Благодаря

+0

Будет ли вектор всегда начинаться с нулей? Знаете ли вы количество блоков, которые у вас есть (всегда 2)? – BillBokeey

+0

Да, он будет начинаться с 0 каждый раз –

+0

В вашем примере два блока из 1 не имеют одинакового размера (сначала имеет 6 элементов, а второй - 5). Это опечатка или может произойти в вашем векторе данных? Затем вам не нужно создавать несколько векторов, так как 'mean' может работать по заданному размеру – BillBokeey

ответ

3

(Надеюсь) правильная версия:

M = logical(A(:, 2)); 
is_start = [M(1); ~M(1:end-1) & M(2:end)]; 
is_start = is_start(M); 
A_valid = A(M, 1); 
group_idx = cumsum(is_start); 
group_start_idx = find(is_start); 
sub_idx = (1:numel(is_start))' - group_start_idx(group_idx)+1; 
means = accumarray(sub_idx, A_valid, [], @mean); 

Существует, возможно, немного аккуратнее способ сделать это с одним или двумя меньше шагов, но это должно работать.

Снять урок дома: использовать cumsum чаще!

[исходный неправильный ответ удален]

+0

'M (0)', ouch ^^ – BillBokeey

+0

Я думаю, что то, что хочет OP, является средним по элементу из двух блоков по элементу (то есть элементу 1 первого блока с элементом 1 второго и т. Д.). Поэтому ваш 'group_idx' должен быть' [0 ..... 0 1 2 3 4 5 6 0 ...... 0 1 2 3 4 5] '. Хорошее использование cumsum и accumarray, хотя, я должен определенно использовать его больше – BillBokeey

+0

Да @BillBokeey правильно, я хочу, чтобы средний элемент по элементу над блоками, таким образом, усреднял первые элементы, а затем усреднял второстепенные элементы, усредняя третьи элементы и так далее на! –