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);