使用具有三维矩阵的单独扩展的bsxfun

jru*_*ren 4 matlab matrix vectorization bsxfun

我正在使用bsxfun大小矩阵之间的单例扩展来向量化操作:

MS: (nms, nls)
KS: (nks, nls)
Run Code Online (Sandbox Code Playgroud)

操作的各值之间的绝对差之和MS(m,l)m1:nmsl1:nls,并且每一个KS(k,l)k1:nks.

我通过代码实现了这一点:

[~, nls] = size(MS);
MS = reshape(MS',1,nls,[]);
R = sum(abs(bsxfun(@minus,MS,KS)));
Run Code Online (Sandbox Code Playgroud)

R很大(nls, nms).

我想将此操作推广到样本列表,因此新的大小将是:

MS: (nxs, nls, nms)
KS: (nxs, nls, nks)
Run Code Online (Sandbox Code Playgroud)

这可以通过for循环轻松实现,for循环执行每个2维矩阵的第一段代码,但我怀疑通过添加新维度来概括先前的代码可以更好地提高性能.

R 将是大小: (nxs, nls, nms)

我试图重塑MS到4个维度但没有成功.这可以通过重塑来完成bsxfun吗?

And*_*eak 6

你可能需要这个:

% generate small dummy data
nxs = 2;
nls = 3;
nms = 4;
nks = 5;
MS = rand(nxs, nls, nms);
KS = rand(nxs, nls, nks);

R = sum(abs(bsxfun(@minus,MS,permute(KS,[1,2,4,3]))),4)
Run Code Online (Sandbox Code Playgroud)

这将产生一个大小的矩阵[2,3,4],即[nxs,nls,nms].每个元素[k1,k2,k3]都对应

R(k1,k2,k3) == sum_k abs(MS(k1,k2,k3) - KS(k1,k2,k))
Run Code Online (Sandbox Code Playgroud)

例如,在我的随机运行中

R(2,1,3)

ans =

   1.255765020150647

>> sum(abs(MS(2,1,3)-KS(2,1,:)))

ans =

   1.255765020150647
Run Code Online (Sandbox Code Playgroud)

诀窍是引入单例尺寸permute:permute(KS,[1,2,4,3])大小[nxs,nls,1,nks],而MS大小[nxs,nls,nms]也隐含大小[nxs,nls,nms,1]:假设MATLAB中的每个数组都具有可数无限数量的尾随单例尺寸.从这里可以很容易地看到如何bsxfun将大小数组合在一起,[nxs,nls,nms,1][nxs,nls,1,nks]分别获得一个大小的数组[nxs,nls,nms,nks].沿着维度4总结密封交易.


我在评论中指出,permute求和指数可能更快.事实证明,这本身会使代码运行得更慢.但是,通过重新整形数组以减小尺寸大小,整体性能会提高(由于最佳内存访问).比较一下:

% generate larger dummy data
nxs = 20;
nls = 30;
nms = 40;
nks = 500;
MS = rand(nxs, nls, nms);
KS = rand(nxs, nls, nks);

MS2 = permute(MS,[4 3 2 1]);
KS2 = permute(KS,[3 4 2 1]);
R3 = permute(squeeze(sum(abs(bsxfun(@minus,MS2,KS2)),1)),[3 2 1]);
Run Code Online (Sandbox Code Playgroud)

我所做的是将求和nks维度放在第一位,然后按降序排列其余维度.这可以自动完成,我只是不想让这个例子过于复杂.在您的使用案例中,您可能会知道尺寸的大小.

使用上述两个代码的运行时:原始值为0.07028秒,重新排序的值为0.051162秒(最好为5个).不幸的是,现在更大的例子不适合我.

  • '4D`置换!尼斯! (2认同)