关于 ndarray 的形状不可知切片 [英] On shape-agnostic slicing of ndarrays

查看:32
本文介绍了关于 ndarray 的形状不可知切片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这篇文章中,我使用术语 slice 来指代 n 维数组 的子数组 B_iA 使得 size(B_i, d) 为 1,对于某个维度 d.Asize(A, d) 这样的切片组成,沿着维度 d 连接.

In this post, I'm using the term slice to refer to a subarray B_i of an n-dimensional array A such that size(B_i, d) is 1, for some dimension d. A consists of size(A, d) such slices, concatenated along dimension d.

例如,如果 ndims(A) 是 6 而 d 是 3,那么形式的表达式

For example, if ndims(A) is 6 and d is 3, then the expressions of the form

A(:, :, i, :, :, :)

for i in 1:size(A, d) 代表组成的所有切片(沿维度d)A.

for i in 1:size(A, d) represent all the slices (along dimension d) that make up A.

A(:, :, i, :, :, :) 这样的表达式的问题在于它不能符号化推广到沿不同维度的切片from 3 in 数组中的维数与 6 不同.例如,要沿维数 2 获取 A 的切片,需要不同的表达式 A(:, i, :,:, :, :).这意味着此类表达式在不知道要从中提取切片的某个数组的形状的代码中是无用的.

The problem with an expression like A(:, :, i, :, :, :) is that it cannot be generalized symbolically to slices along a dimension different from 3 in arrays having a number of dimensions different from 6. E.g., to get A's slices along dimension 2, one would need a different expression, A(:, i, :, :, :, :). This means that such expressions are useless in code that is agnostic about the shape of some array from which slices are to be extracted.

下面的函数是我的 matlab-noob 尝试实现与形状无关的切片.(slice这个名字已经被占用了,所以我把这个函数叫做hslice,是hyperslice的缩写.)这个函数的策略是对输入数组进行整形放入合适的 3-d 数组,沿重构数组的第二维取所需切片,并将结果整形为原始输入数组的切片形状.

The function below is my matlab-noob attempt to implement shape-agnostic slicing. (The name slice is already taken, hence I called the function hslice, short for hyperslice.) The function's strategy is to reshape the input array into a suitable 3-d array, take the desired slice along the reshaped array's second dimension, and reshape the result to have the shape of a slice from the original input array.

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

是否有内置的或至少更有效的方法来实现相同的结果(以与形状无关的方式)?

Is there a built-in, or at least a more efficient, way to achieve the same result (in a shape-agnostic way)?

推荐答案

是的.您可以使用取消引用的元胞数组和逗号分隔列表"之间的等效性,以及您可以使用字符 ':' 作为索引来动态构造 A(:, :, :, i, :, ...) 调用任意维度.

Yeah. You can use the equivalence between dereferenced cell arrays and "comma-separated lists", and the fact that you can use a char ':' as an index to dynamically construct that A(:, :, :, i, :, ...) invocation for arbitrary dimensions.

function out = slice(A, ix, dim)

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

这将完全泛化,并且将执行与原始静态 A(:, :, i, :, ...) 表达式完全相同的切片"索引操作,除了开销摆弄这些字符串来设置它.

This will generalize fully, and will do exactly the same "slice" indexing operation as the original static A(:, :, i, :, ...) expression, aside from the overhead of twiddling those strings to set it up.

或者,如果您愿意,您可以使用 sprintfA(:, :, i, :, ...) 构造为字符串,然后在其上调用 eval().但我喜欢尽可能避免 eval.

Or if you wanted to, you could just use sprintf to construct that A(:, :, i, :, ...) as a string and then call eval() on it. But I like to avoid eval if at all possible.

请注意,您的原始实现使用的是快速操作,并且应该执行得很好,与此操作一样快.我发布这个只是因为我认为它非常具有可读性,确实像最初提出的那样回答了你的问题,并且它可以应用于其他有用的东西.

Note that your original implementation is using fast operations and should perform just fine, about as fast as this one. I'm just posting this because I think it's very readable, does answer your question as originally posed, and it could be applied to other useful stuff.

您也可以使用相同的下标单元格技术作为左值分配给数组的切片.但是,您不能直接重用 slice 函数,因为它返回提取的数组子集,而不是左值引用.所以你可以创建一个非常相似的函数来完成赋值.

You can also use this same subscripts-in-a-cell technique as an lvalue to assign in to slices of an array. You can't reuse the slice function directly, though, since it returns an extracted subset of the array, and not an lvalue reference. So you can make a very similar function that does the assignment itself.

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;

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

In practice, you might also want a function that just returns the computed indexes in a cell array, so you could carry those around and use them repeatedly for assignment and referencing.

function out = slice_subs(A, ix, dim)

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

这篇关于关于 ndarray 的形状不可知切片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆