2016-10-13 2 views
1

Скажем Х является данный вектор:Как найти число вхождений подмножества элементов в векторе без использования петель в MATLAB?

X=[1 
     2 
     4 
     2 
     3 
     1 
     4 
     5 
     2 
     4 
     5]; 

и Y представляет собой заданное подмножество элементов из X:

Y=[3 
    4 
    5]; 

Требуемая мощность является количество раз элементы в Y происходят в X:

out=[1 
    3 
    2]; 

Мое решение, чтобы сделать это было бы использовать for цикл:

for i=1:size(X,1) 
    temp = X(X(:,1)==Y(i,1),:); 
    out(i,1) = size(temp,1); 
end 

Но когда X и Y большие, это неэффективно. Итак, как это сделать быстрее, используя вектологию? Я знаю о hist и histc, но я не могу придумать, как их использовать в этом случае, чтобы получить желаемый результат.

ответ

5

быстрый Вариант

Вы можете использовать bsxfun в сочетании с sum, чтобы вычислить этот

sum(bsxfun(@eq, Y, X.'), 2) 

Объяснение

В этом примере bsxfun выполняет заданную операцию на каждой комбинации элементов в X и Y. Операцией, которую мы используем, является eq (проверка равенства). Результатом является матрица, которая имеет строку для каждого элемента в Y и столбец для каждого элемента в X. Он будет иметь значение 1, если элемент в X равен элементу в Y, который соответствует данной строке.

bsxfun(@eq, Y, X.') 

% 0  0  0  0  1  0  0  0  0  0  0 
% 0  0  1  0  0  0  1  0  0  1  0 
% 0  0  0  0  0  0  0  1  0  0  1 

Затем можно суммировать по столбцам, чтобы подсчитать количество элементов в X, которые были равны заданному значению в Y.

sum(bsxfun(@eq, Y, X.'), 2) 

% 1 
% 3 
% 2 

В новых версиях MATLAB (с R2016b), вы можете опустить bsxfun поскольку операция равенства будет автоматически транслироваться.

sum(Y - X.', 2) 

А Память-Efficient Опция

Первый вариант не является наиболее эффективным, поскольку он требует создания матрицы, которая является [numel(Y), numel(X)] элементы большой. Другой способ, который может быть больше памяти, может быть эффективно использовать второй выход ismember в сочетании с accumarray

[tf, ind] = ismember(X, Y); 
counts = accumarray(ind(tf), ones(sum(tf), 1), [numel(Y), 1], @numel); 

Объяснение

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

[tf, ind] = ismember(X, Y); 

% 0 0 1 0 1 0 1 1 0 1 1 
% 0 0 2 0 1 0 2 3 0 2 3 

Мы можем использовать второй вход для группировки одинаковых значений вместе. Функция accumarray выполняет именно это, она использует переменную ind выше для определения групп, а затем применяет данную операцию к каждой группе. В нашем случае мы хотим просто определить количество элементов внутри каждой группы. Таким образом, чтобы сделать это, мы можем перейти на второй вход размер ind входа (минус те, которые не соответствуют) из них, а затем использовать numel как операция (подсчитывает число в каждой группе)

counts = accumarray(ind(tf), ones(sum(tf), 1), [numel(Y), 1], @numel); 

% 1 
% 3 
% 2 
+0

Я пытался. Но я получаю ошибку «Out of memory». – Kristada673

+0

@ Kristada673 Насколько велики 'X' и' Y'? – Suever

+0

Довольно большой. X имеет 5,88 миллиона строк, а Y - 1,1 миллиона строк. – Kristada673

Смежные вопросы