在矩阵中找到水平或垂直放置的向量
Posted
技术标签:
【中文标题】在矩阵中找到水平或垂直放置的向量【英文标题】:Find a vector placed horizontally or vertically in a matrix 【发布时间】:2017-11-25 16:52:39 【问题描述】:我试图在A
的大矩阵中找到一个向量B
。B
可以是A
的多行一列,也可以是@987654325 的多列一行@。
例如:
A = [56 55 53 52 53;
49 45 44 45 47;
33 30 31 34 35;
34 34 27 24 26;
44 48 45 35 24;
56 57 57 53 39;
62 62 62 60 55;
62 61 61 54 47;
49 47 42 40 32;
47 42 44 45 40];
B = [34 27 24];
我需要一个返回行和列索引的函数,例如: find(A, B) → 第 4 行,第 2 到第 4 列(对于给定的示例)。
如何做到这一点?
【问题讨论】:
【参考方案1】:我们可以将矩阵typecastchar
并使用strfind 搜索矩阵:
%Horizontal search
A_str_h = typecast(A.','char');
B_str = typecast(B,'char');
charsize = numel(B_str)/numel(B);
pos_h = strfind(A_str_h,B_str)-1;
pos_h = pos_h(mod(pos_h,charsize)==0)/charsize+1;
[col_h row_h] = ind2sub(flip(size(A)),pos_h);
idx_h = col_h <= (size(A,2)-numel(B)+1);
row_h = row_h(idx_h);
col_h = col_h(idx_h);
%Vertical search
A_str_v = typecast(A,'char');
B_str = typecast(B,'char');
charsize = numel(B_str)/numel(B);
pos_v = strfind(A_str_v,B_str)-1;
pos_v = pos_v(mod(pos_v,charsize)==0)/charsize+1;
[row_v col_v] = ind2sub(size(A),pos_v);
idx_v = row_v <= (size(A,1)-numel(B)+1);
row_v = row_v(idx_v);
col_v = col_v(idx_v);
使用convn的另一种解决方案:
n = numel(B);
C = A == reshape(B,1,1,n);
mask_h = permute(eye(n),[3 2 1]);
mask_v = permute(eye(n),[1 3 2]);
[xh yh]=find(convn(C,mask_h,'valid')==n);
[xv yv]=find(convn(C,mask_v,'valid')==n);
[xh yh]
代表横向匹配的起始位置,[xv yv]
代表纵向匹配的起始位置。
这是测试不同方法的结果,将A
设置为[2750 * 1250]
矩阵和B
的不同大小:
结果表明CONVN
的效率低于其他方法,不适用于大尺寸的数组,而STRFIND
适用于所有尺寸的数组。
*方法在 Octave 中测试。
【讨论】:
【参考方案2】:rahnema1 和 m7913d 之间的基准测试
水平和垂直匹配
使用timeit
为给定示例(小A)和100^2
更大的示例(大A)对rahnema1 和m7913d 的解决方案进行基准测试,给出结果如下:
Method | Small A | Large A
--------------------------------
rahnema1 | 4.0416e-05 | 0.0187
m7913d | 2.5242e-05 | 0.0129
请注意,m7913d 的解决方案要快约 50%。
仅水平(或垂直)匹配
如果只对横向匹配感兴趣,会得到以下结果:
Method | Small A | Large A
--------------------------------
rahnema1 | 9.6752e-06 | 0.0115
m7913d | 5.8634e-06 | 0.0056
在这种情况下,m7913d 的解决方案更加有利,速度提高了约 100%。
完整的基准代码
A=[56 55 53 52 53;
49 45 44 45 47;
33 30 31 34 35;
34 34 27 24 26;
44 48 45 35 24;
56 57 57 53 39;
62 62 62 60 55;
62 61 61 54 47;
49 47 42 40 32;
47 42 44 45 40];
B=[34 27 24];
A_large = repmat(A, 100, 100);
t_m7913d = timeit(@() m7913d(A, B))
t_rahnema = timeit(@() rahnema1(A, B))
t_large_m7913d = timeit(@() m7913d(A_large, B))
t_large_rahnema = timeit(@() rahnema1(A_large, B))
function [row_h, col_h, row_v, col_v] = m7913d(A, B)
Ah = true(size(A) - [0 length(B)-1]);
Av = true(size(A) - [length(B)-1 0]);
for i=1:length(B)
Ah= Ah & A(:, i:end-3+i) == B(i);
Av= Av & A(i:end-3+i, :) == B(i);
end
[row_h, col_h] = find(Ah);
[row_v, col_v] = find(Av);
end
function [row_h, col_h, row_v, col_v] = rahnema1(A, B)
n = numel(B);
C = A == reshape(B,1,1,n);
mask_h = permute(eye(n),[3 2 1]);
mask_v = permute(eye(n),[1 3 2]);
[row_h, col_h]=find(convn(C,mask_h,'valid')==n);
[row_v, col_v]=find(convn(C,mask_v,'valid')==n);
end
【讨论】:
【参考方案3】:对于B
的固定大小,可以使用如下方法:
[row, col] = find(A(:, 1:end-2) == B(1) & ...
A(:, 2:end-1) == B(2) & ...
A(:, 3:end) == B(3))
这将返回row = 4
和col = 2
,即B(1)
在A
中的位置。
更多信息请参见Find Array Elements That Meet a Condition。
这可以使用 for 循环扩展到可变大小向量B
:
Ah = true(size(A) - [0 length(B)-1]);
for i=1:length(B)
Ah= Ah & A(:, i:end-length(B)+i) == B(i);
end
[row, col] = find(Ah);
这可以很容易地扩展到找到B
水平和垂直的出现,如下所示:
Ah = true(size(A) - [0 length(B)-1]);
Av = true(size(A) - [length(B)-1 0]);
for i=1:length(B)
Ah= Ah & A(:, i:end-3+i) == B(i);
Av= Av & A(i:end-3+i, :) == B(i);
end
[row_h, col_h] = find(Ah);
[row_v, col_v] = find(Av);
基准测试
请注意,尽管如此,我使用的是 for 循环,但这种方法比 rahnema1 的解决方案要快,尤其是如果您只对水平(或垂直)匹配感兴趣。请查看the benchmark 了解更多信息。
【讨论】:
以上是关于在矩阵中找到水平或垂直放置的向量的主要内容,如果未能解决你的问题,请参考以下文章