matlab: деление вектора на перекрывающиеся фрагменты фиксированного размера

У меня есть вектор, который я хотел бы разделить на перекрывающиеся субвекторы размера cs в смену sh, Представьте, что входной вектор:

v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]

учитывая chunksize из 4 (cs=4) и смещение 2 (sh=2), результат должен выглядеть так:

[1 2 3 4]
[3 4 5 6]
[5 6 7 8]
[7 8 9 10]
[9 10 11 12]

обратите внимание, что входной вектор не обязательно делится на chunksize и поэтому некоторые подвекторы отбрасываются. Есть ли быстрый способ вычислить это, без необходимости использования, например, for цикл? В соответствующем посте я нашел, как это сделать, но при рассмотрении непересекающихся подвекторов.

5 ответов

Вы можете использовать функцию bsxfun следующим образом:

v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;

A = v(bsxfun(@plus,(1:cs),(0:sh:length(v)-cs)'));

Вот как это работает. bsxfun применяет некоторые основные функции к 2 массивам и выполняет некоторые repmat - как если бы размеры входов не подходили. В этом случае я генерирую индексы первого чанка и добавляю смещение каждого чанка. Поскольку один вход представляет собой вектор-строку, а другой - вектор-столбец, результат представляет собой матрицу. Наконец, при индексации вектора с помощью матрицы, результатом является матрица, а это именно то, что вы ожидаете.

И это однострочник, (почти) всегда весело:).

У вас есть набор инструментов для обработки сигналов? Тогда команда buffer, Сначала посмотрите на голый вывод:

buffer(v, 4, 2)

ans =
     0     1     3     5     7     9    11
     0     2     4     6     8    10    12
     1     3     5     7     9    11    13
     2     4     6     8    10    12     0

Это, безусловно, правильная идея, с небольшой настройкой, необходимой для получения именно того результата, который вы хотите:

[y z] = buffer(v, 4, 2, 'nodelay');
y.'

ans =
     1     2     3     4
     3     4     5     6
     5     6     7     8
     7     8     9    10
     9    10    11    12

Тем не менее, рассмотрите возможность оставить векторы по столбцам, так как это лучше всего подходит для большинства случаев использования. Например, среднее значение каждого окна просто mean матрицы, так как столбец по умолчанию.

Я полагаю, что самый простой способ - это цикл. Векторизованное решение может быть быстрее, но если результат будет правильно распределен, цикл также должен работать прилично.

v = 1:13
cs = 4;
sh = 2;

myMat = NaN(floor((numel(v) - cs) / sh) + 1,cs);
count = 0;

for t = cs:sh:numel(v)
   count = count+1;
   myMat(count,:) = v(t-cs+1:t);
end

Вы можете сделать это с ndgrid:

>> v=1:13; cs=4; sh=2;
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1)
>> chunks = X+Y
chunks =
     1     2     3     4
     3     4     5     6
     5     6     7     8
     7     8     9    10
     9    10    11    12

Хорошая вещь о втором синтаксисе colon оператор (j:i:k), что вам не нужно рассчитывать k точно (например 1:2:6 дает [1 3 5]), если вы планируете отказаться от дополнительных записей, как в этой проблеме. Это автоматически идет в j+m*i, где m = fix((k-j)/i);

Другой тест:

>> v=1:14; cs=5; sh=2; % or v=1:15 or v=1:16
>> [Y,X]=ndgrid(1:(cs-sh):(numel(v)-cs+1),0:cs-1); chunks = X+Y
chunks =
     1     2     3     4     5
     4     5     6     7     8
     7     8     9    10    11
    10    11    12    13    14

И новая строка будет формироваться с v=1:17, Это обрабатывает все случаи по мере необходимости?

Как насчет этого? Сначала я генерирую стартовые индексы на основе cs а также sh для вырезания отдельных векторов из вектора полной длины, то я удаляю все индексы, для которых idx+cs будет превышать длину вектора, а затем я разрезаю отдельные субвекторы через arrayfun и затем преобразовать их в матрицу:

v=[1 2 3 4 5 6 7 8 9 10 11 12 13]; % A=[1:13]
cs=4;
sh=2;

idx = 1:(cs-sh):length(v);
idx = idx(idx+cs-1 <= length(v))
A = arrayfun(@(i) v(i:(i+cs-1)), idx, 'UniformOutput', false);
cell2mat(A')

Например, для cs=5; sh=3; это дало бы:

idx =

     1     3     5     7


ans =

     1     2     3     4     5
     3     4     5     6     7
     5     6     7     8     9
     7     8     9    10    11

В зависимости от того, где значения cs; sh возможно, вы захотите ввести простую проверку ошибок, чтобы cs > 0; так же как sh < cs, sh < 0 было бы возможно теоретически, если вы хотите оставить некоторые значения между ними.

РЕДАКТИРОВАТЬ: Исправлена ​​очень маленькая ошибка, теперь должен быть запущен для различных комбинаций sh и cs.

Другие вопросы по тегам