找到两个 Matlab 矩阵之间的相等行
Find equal rows between two Matlab matrices
我在 Matlab 中有一个大小为 GxN
的矩阵 index
和一个大小为 MxN
的矩阵 A
。
让我在提出问题之前先举个例子。
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
如果行 A(m,:)
等于 index(g,:)
且为零,我希望你帮助构建一个大小为 GxM
且 Response(g,m)=1
的矩阵 Response
除此以外。
继续上面的例子
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
),该命令非常慢。我知道我无法获得巨大的速度,但欢迎任何可以改进的东西。
MATLAB 有很多函数 working with sets, including setdiff
, intersect
, union
etc. In this case, you can use the ismember
函数:
[~, 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
方法一:计算距离
如果您有统计工具箱:
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.
您可以 reshape
矩阵,使每一行都位于第 3 个维度上。然后我们可以使用隐式扩展(参见 R2016b 或更早版本的 bsxfun
)来使所有元素相等,并使用 all
在行上聚合(即,如果给定行不完全相等则为 false)。
Response = all( reshape( index, [], 1, size(index,2) ) == reshape( A, 1, [], size(A,2) ), 3 );
您甚至可以通过在另一个维度中使用 all
来避免一些重塑,但我更容易以这种方式形象化它。
我在 Matlab 中有一个大小为 GxN
的矩阵 index
和一个大小为 MxN
的矩阵 A
。
让我在提出问题之前先举个例子。
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
如果行 A(m,:)
等于 index(g,:)
且为零,我希望你帮助构建一个大小为 GxM
且 Response(g,m)=1
的矩阵 Response
除此以外。
继续上面的例子
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
),该命令非常慢。我知道我无法获得巨大的速度,但欢迎任何可以改进的东西。
MATLAB 有很多函数 working with sets, including setdiff
, intersect
, union
etc. In this case, you can use the ismember
函数:
[~, 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
方法一:计算距离
如果您有统计工具箱:
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.
您可以 reshape
矩阵,使每一行都位于第 3 个维度上。然后我们可以使用隐式扩展(参见 R2016b 或更早版本的 bsxfun
)来使所有元素相等,并使用 all
在行上聚合(即,如果给定行不完全相等则为 false)。
Response = all( reshape( index, [], 1, size(index,2) ) == reshape( A, 1, [], size(A,2) ), 3 );
您甚至可以通过在另一个维度中使用 all
来避免一些重塑,但我更容易以这种方式形象化它。