Лучший способ извлечь все строки из матрицы A, которые содержат элемент матрицы B
Матрица A - это моя начальная матрица, в которой хранятся данные, записанные с моего MPU6050 и GPS на SD-карте (широта, долгота, время, топор, Ay, Az, Gx,Gy,Gz).
Я рассчитал стандартное отклонение Az для размера окна 5 и определил все элементы, которые удовлетворяют условию (> порог).
Затем в матрице "large_windows" я сохранил индекс всех Az в окне, которые удовлетворяют условию.
Из матрицы "large_windows" я вычислил новую матрицу B со всеми строками из матрицы A, которые содержат элементы матрицы "large_windows".
Я думаю, что мой код эффективен, но очень уродлив и хаотичен, плюс я все еще не очень практичен в индексировании, но я хочу изучить его.
1. Существует ли лучшее решение?
2. Можно ли использовать логическую индексацию? Как? Это эффективно *?
Вот мой код, это упрощенный пример с общим условием, чтобы лучше понять всю концепцию, а не только мою конкретную ситуацию, начиная с предложений предыдущей проблемы (как создать скользящее окно
%random matix nXm
a=rand(100,6);
%window dimension
window_size=4;
%overlap between two windows
overlap=1;
%increment needed
step=window_size - overlap;
%std threshold
threshold=0.3;
std_vals= NaN(size(a,1),1);
%The sliding window will analyze only the 5th column
for i=1: step: (size(a,1)-window_size)
std_vals(i)=std(a(i:(i+window_size-1),5));
end
% finding the rows with standard deviation larger than threshold
large_indexes = find(std_vals>threshold);
%Storing all the elements that are inside the window with std>threshold
large_windows = zeros(numel(large_indexes), window_size);
for i=1:window_size
large_windows(:,i) = large_indexes + i - 1;
end
% Starting extracting all the rows with the 5th column outlier elements
n=numel(large_windows);
%Since i will work can't know how long will be my dataset
%i need to knwo how is the "index distance" between two adjacent elements
% in the same row [es. a(1,1) and a(1,2)]
diff1=sub2ind(size(a),1,1);
diff2=sub2ind(size(a),1,2);
l_2_a_r_e = diff2-diff1 %length two adjacent row elements
large_windows=large_windows'
%calculating al the index of the element of a ith row containing an anomaly
for i=1:n
B{i}=[a(large_windows(i))-l_2_a_r_e*4 a(large_windows(i))-l_2_a_r_e*3 a(large_windows(i))-l_2_a_r_e*2 a(large_windows(i))-l_2_a_r_e*1 a(large_windows(i))-l_2_a_r_e*0 a(large_windows(i))+l_2_a_r_e];
end
C= cell2mat(B');
Я также прочитал некоторый вопрос, прежде чем опубликовать его, но это было к конкретному
B не входит в A, поэтому этот вопрос бесполезен. Найти дополнение фрейма данных (против объединения)
Я не знаю как пользоваться ismember
в этом конкретном случае
Я надеюсь, что мой рисунок мог бы лучше объяснить мою проблему:)
1 ответ
Вот новый подход к достижению результата, которого вы на самом деле хотели достичь. Я исправил 2 ошибки, которые вы сделали, и заменил все циклы for на bsxfun
это очень эффективная функция для подобных вещей. Для Matlab R2016b или новее вы также можете использовать неявное расширение вместо bsxfun
,
Моя запускает у вас реализацию скользящего окна. Вместо вашего for
, вы можете использовать
stdInds=bsxfun(@plus,1:step:(size(a,1)-overlap),(0:3).');
std_vals=std(a(sub2ind(size(a),stdInds,repmat(5,size(stdInds)))));
Вот. Bsxfun создает массив, содержащий строки ваших окон. Он содержит 1 виндо в каждой колонке. Эти строки должны быть преобразованы в линейный индекс a
-array для получения массива значений, которые могут быть переданы std
-функции. В своей реализации вы допустили небольшую ошибку, потому что ваш for
петля заканчивается в size(a,1)-window_size
и на самом деле должен был закончиться в size(a,1)-overlap
потому что в противном случае вы пропустите последнее окно.
Теперь, когда мы получили значения std окон, мы можем проверить, какие из них больше, чем ваш предварительно определенный порог, и затем преобразовать их обратно в соответствующие строки:
highStdWindows=find(std_vals_2>threshold);
highStdRows=bsxfun(@plus,highStdWindows*step-step+1,(0:3).');
highStdWindows
содержит индексы окон, которые имеют высокие значения Std. В следующей строке мы вычисляем начальные строки этих окон, используя highStdWindows*step-step+1
а затем мы вычисляем другие строки, которые соответствуют каждому окну, используя bsxfun
снова.
Теперь мы добрались до фактической ошибки в вашем коде. Эта линия прямо здесь
B{i}=[a(large_windows(i))-l_2_a_r_e*4 a(large_windows(i))-l_2_a_r_e*3 a(large_windows(i))-l_2_a_r_e*2 a(large_windows(i))-l_2_a_r_e*1 a(large_windows(i))-l_2_a_r_e*0 a(large_windows(i))+l_2_a_r_e];
не делает то, что хотел. К сожалению, здесь вы пропустили пару скобок. Таким образом, вы берете элемент large_windows(i)'матрицы a
и вычесть 4*l_2_a_r_e
от него. То, что вы хотели написать, было
B{i}==[a(large_windows(i)-l_2_a_r_e*4) % and so on
Таким образом, вы бы вычли 4*l_2_a_r_e
из индекса, который вы передаете a
, Это все равно будет неправильно, потому что в large_windows вы храните номера строк, а не линейные индексы, соответствующие матрице a
,
Тем не менее, это может быть достигнуто намного проще, используя индексирование по подписке вместо линейного индексирования:
rowList=reshape(highStdRows,1,[]);
C=a(rowList,:); % all columns (:) and from the rows in rowList
Эти две простые строки говорят Matlab взять все строки, которые хранятся в highStdRows
со всеми столбцами (выражается :
). При этом, если есть два смежных окна с высокими значениями Std, вы получите перекрывающиеся строки дважды. Если вы не хотите этого, вы можете использовать этот код:
rowList=unique(reshape(highStdRows,1,[]));
C=a(rowList,:);
Если вы хотите получить дополнительную информацию о том, как работает индексация в Matlab, взгляните на сообщение LuisMendo на эту тему.