Найти равные строки между двумя матрицами Matlab - PullRequest
0 голосов
/ 03 октября 2018

У меня есть матрица index в Matlab с размером GxN и матрица A с размером MxN.

Позвольте мне привести пример перед тем, как представить мой вопрос.

clear
N=3;
G=2;
M=5;

index=[1  2  3;
       13 14 15]; %GxN

A=[1  2  3; 
   5  6  7; 
   21 22 23; 
   1  2  3;
   13 14 15]; %MxN

Я хотел бы, чтобы вы помогли построить матрицу Response с размером GxM с Response(g,m)=1, если строка A(m,:) равно index(g,:) и равно нулю в противном случае.

Продолжая приведенный выше пример

Response= [1 0 0 1 0; 
           0 0 0 0 1]; %GxM

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

Response=permute(any(all(bsxfun(@eq, reshape(index.', N, [], G), permute(A, [2 3 4 1])), 1), 2), [3 4 1 2]);

Тем не менее, команда очень медленная для моих реальных размеров матрицы (N=19, M=500, G=524288).Я понимаю, что не смогу набрать огромную скорость, но все, что может улучшить это, приветствуется.

Ответы [ 3 ]

0 голосов
/ 03 октября 2018

Подход 1: вычисление расстояний

Если у вас есть Панель инструментов статистики:

Response = ~(pdist2(index, A));

или:

Response = ~(pdist2(index, A, 'hamming'));

Это работает, потому что pdist2 вычисляет расстояние между каждой парой строк.Равные строки имеют расстояние 0.Логическое отрицание ~ дает 1 для этих пар строк и 0 в противном случае.

Подход 2: сокращение строк до уникальных целочисленных меток

Этот подход быстрее на моей машине:

[~,~,u] = unique([index; A], 'rows');
Response = bsxfun(@eq, u(1:G), u(G+1:end).');

Работает, сокращая строки до уникальных целочисленных меток (используя третий вывод unique) и сравнивая последние вместо первых.

Для значений вашего размера это занимает примерно 1 секунду на моем компьютере:

clear
N = 19; M = 500; G = 524288;
index = randi(5,G,N); A = randi(5,M,N);
tic
[~,~,u] = unique([index; A], 'rows');
Response = bsxfun(@eq, u(1:G), u(G+1:end).');
toc

дает

Elapsed time is 1.081043 seconds.
0 голосов
/ 03 октября 2018

Вы можете reshape матрицы, чтобы каждая строка вместо этого лежала вдоль 3-го измерения.Тогда мы можем использовать неявное расширение (см. bsxfun для R2016b или ранее) для равенства всех элементов и all для агрегирования по строкам (т. Е. False, если не все равны для данной строки).

Response = all( reshape( index, [], 1, size(index,2) ) == reshape( A, 1, [], size(A,2) ), 3 ); 

Возможно, вам даже удастся избежать некоторого изменения формы, используя all в другом измерении, но мне проще представить его таким образом.

0 голосов
/ 03 октября 2018

MATLAB имеет множество функций для работы с наборами , включая setdiff, intersect, union и т. Д. В этом случае вы можете использовать ismember function:

[~, Loc] = ismember(A,index,'rows');

Что дает:

Loc =
     1
     0
     0
     1
     2

И Response будет построен следующим образом:

Response = (1:size(index,1) == Loc).';

Response =
  2×5 logical array
   1   0   0   1   0
   0   0   0   0   1
...