为了账号安全,请及时绑定邮箱和手机立即绑定

关于ndarray的形状不可知切片

关于ndarray的形状不可知切片

长风秋雁 2019-11-19 10:09:15
在这篇文章中,我使用切片一词来指代B_i某个维度的n维数组的子数组,A例如size(B_i, d)1 d。 A由此size(A, d)类切片组成,这些切片沿着维度串联在一起d。例如,如果ndims(A)为6且d为3,则该形式的表达式A(:, :, i, :, :, :)for iin 1:size(A, d)表示组成的所有切片(沿维度d)A。像这样的表达式存在的问题A(:, :, i, :, :, :)是,它不能被符号化地概括为具有多个不同于6的维数的数组中沿3的维数A的切片。例如,要获得沿2的维的切片,则需要一个不同的表达式,A(:, i, :, :, :, :)。这意味着这样的表达式在对要从中提取切片的某些数组的形状不可知的代码中毫无用处。下面的功能是我的matlab-noob尝试实现形状不可知的切片。(名称slice已经被使用,因此我将其称为函数hslice,简称hyperslice。)函数的策略是将输入数组重塑为合适的3-d数组,沿着重塑后的数组的第二维获取所需的切片,并将结果重塑为具有原始输入数组的切片形状。function out = hslice(ndarray, d, i)    sz = size(ndarray);    pfx = sz(1:d-1);    % dimensions before d    sfx = sz(d+1:end);  % dimensions after d    tmp = reshape(ndarray, prod(pfx), sz(d), prod(sfx));    out = reshape(tmp(:, i, :), [pfx 1 sfx]);end是否有内置的或至少更有效的方式来实现相同的结果(与形状无关的方式)?
查看完整描述

3 回答

?
ibeautiful

TA贡献1993条经验 获得超5个赞

是的 您可以使用取消引用的单元格数组和“逗号分隔的列表”之间的等价关系,也可以使用char':'作为索引来动态构造A(:, :, :, i, :, ...)任意维度的调用这一事实。


function out = slice(A, ix, dim)


subses = repmat({':'}, [1 ndims(A)]);

subses{dim} = ix;

out = A(subses{:});

这将完全概括化A(:, :, i, :, ...),除了将这些字符串打乱以进行设置之外,还将执行与原始静态表达式完全相同的“切片”索引操作。


或者,如果您愿意,可以只将sprintf其构造A(:, :, i, :, ...)为字符串,然后调用eval()它。但我想尽可能避免eval。


请注意,您最初的实现使用的是快速操作,并且应该执行得很好,大约和这个操作一样快。我之所以发布此内容,是因为我认为它非常易读,确实可以回答您最初提出的问题,并且可以应用于其他有用的内容。


分配给切片

您还可以使用与单元格相同的下标作为左值将其分配给数组的切片。但是,您不能直接重用slice函数,因为它返回数组的提取子集,而不是左值引用。因此,您可以创建一个非常相似的函数来执行分配。


function A = slice_assign(A, ix, dim, B)

%SLICE_ASSIGN Assign new values to a "slice" of A


subses = repmat({':'}, [1 ndims(A)]);

subses{dim} = ix;

A(subses{:}) = B;

在实践中,您可能还需要一个仅返回单元格数组中计算出的索引的函数,因此您可以随身携带这些索引,并重复使用它们进行赋值和引用。


function out = slice_subs(A, ix, dim)


subses = repmat({':'}, [1 ndims(A)]);

subses{dim} = ix;

out = subses;


查看完整回答
反对 回复 2019-11-19
?
阿晨1998

TA贡献2037条经验 获得超6个赞

您可以尝试permute,并setdiff以该维度移动到一贯立场:


function out = hslice(ndarray, d, i)

subdims = setdiff(1:ndims(ndarray),d);

sz = size(ndarray);

outsz = sz(subdims);

order = [d subdims];

ndarray = permute(ndarray,order);

out = reshape(ndarray(i,:),outsz);

end

例如:


d = 3; i = 2;

nd = randi(23,3,3,3,2);

out = hslice(nd,d,i);   % out = squeeze(nd(:,:,i,:)) for d=3

但是,在切片之前,数据将被重写,而不是与问题中的代码一起被重写。因此,我实际上会选择OP!


查看完整回答
反对 回复 2019-11-19
?
手掌心

TA贡献1942条经验 获得超3个赞

如果您要重写subsref,则可以为普通类不支持的索引类型定义行为。例如,您可以{}支持任意字符串输入,而不仅限于':',也可以.采用数字作为参数。我用了一段时间,使它{}成为内存关系类的RESTRICT操作,并.成为支持按名称或位置索引列的PROJECT。例如selection = r{''WHERE trade_date > today & price < 14''};

查看完整回答
反对 回复 2019-11-19
  • 3 回答
  • 0 关注
  • 643 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信