matlab: исключить элементы из массива
у меня довольно большой массив. Чтобы сделать вещи простыми, давайте упростим его до:
A = [1 1 1 1 2 2 3 3 3 3 4 4 5 5 5 5 5 5 5 5];
Итак, существует группа из 1-х (4 элемента), 2-х (2 элемента), 3-х (4 элемента), 4-х (2 элемента) и 5-х (8 элементов). Теперь я хочу сохранить только столбцы, которые принадлежат группе из 3 или более элементов. Так что это будет похоже:
B = [1 1 1 1 3 3 3 3 5 5 5 5 5 5 5 5];
Я делал это с помощью на цикл, сканирование отдельно 1-х, 2-х, 3-х и так далее, но его чрезвычайно медленно с большими массивами... Спасибо за любой предложения, как сделать это более эффективным способом :) Искусство.
4 ответов
вот мой двухстрочный
counts = accumarray(A', 1);
B = A(ismember(A, find(counts>=3)));
accumarray используется для подсчета отдельных членов A. find извлекает те, которые соответствуют вашему критерию "3 или более элементов". Наконец, ismember сообщает вам, где они находятся в A. обратите внимание, что A не нужно сортировать. Конечно, accumarray работает только для целочисленных значений в А.
общий подход
если ваш вектор не обязательно отсортирован, то вам нужно запустить, чтобы подсчитать количество вхождений каждого элемента в векторе. У вас есть histc
только для этого:
elem = unique(A);
counts = histc(A, elem);
B = A;
B(ismember(A, elem(counts < 3))) = []
последняя строка выбирает элементы, которые имеют менее 3 вхождений и удаляет их.
подход для сгруппированного вектора
если ваш вектор "полу-отсортирован", то есть, если похожие элементы в векторе сгруппированы вместе (как в вашем примере), вы можете немного ускорить следующим образом:
start_idx = find(diff([0, A]))
counts = diff([start_idx, numel(A) + 1]);
B = A;
B(ismember(A, A(start_idx(counts < 3)))) = []
опять же, обратите внимание, что вектор не должен быть полностью отсортирован, просто похожие элементы соседствуют друг с другом.
то, что вы описываете, называется выполнить-длина кодировки.
для этого есть программное обеспечение в Matlab на FileExchange. Или вы можете сделать это напрямую следующим образом:
len = diff([ 0 find(A(1:end-1) ~= A(2:end)) length(A) ]);
val = A(logical([ A(1:end-1) ~= A(2:end) 1 ]));
как только у вас есть кодировка длины выполнения, вы можете удалить элементы на основе длины. т. е.
idx = (len>=3)
len = len(idx);
val = val(idx);
а затем декодировать, чтобы получить массив, который вы хотите:
i = cumsum(len);
j = zeros(1, i(end));
j(i(1:end-1)+1) = 1;
j(1) = 1;
B = val(cumsum(j));
вот еще один способ сделать это с помощью встроенных модулей matlab.
% Set up
A=[1 1 1 1 2 2 3 3 3 3 4 4 5 5 5 5 5];
threshold=2;
% Get the unique elements of the array
uniqueElements=unique(A);
% Count haw many times each unique element occurs
counts=histc(A,uniqueElements);
% Write which elements should be kept
toKeep=uniqueElements(counts>threshold);
% Make a logical index
indexer=false(size(A));
for i=1:length(toKeep)
% For every unique element we want to keep select the indices in A that
% are equal
indexer=indexer|(toKeep(i)==A);
end
% Apply index
B=A(indexer);