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

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

问题描述

在本文中,我使用术语 slice 来指代 n 维数组A的子数组B_i,这样size(B_i, d)对于某些尺寸d为1. 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, :, :, :)

表示组成A的所有切片(沿尺寸d).

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

A(:, :, i, :, :, :)这样的表达式的问题在于,不能将它象征性地泛化为具有多个不同于6的维的数组中沿一个不同于3的维的切片.例如,获得A沿维度2的切片,将需要一个不同的表达式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数组,并沿着重塑后的形状获取所需的切片数组的 second 维度,并调整结果的形状以使其具有原始输入数组中的切片形状.

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)?

推荐答案

是的.您可以使用取消引用的单元格数组和逗号分隔的列表"之间的等价关系,并且可以使用char':'作为索引来动态构造任意尺寸的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.

或者,如果您愿意,可以只使用sprintf将该A(:, :, 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天全站免登陆