Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab 关于阵列的形状不可知切片_Matlab_Multidimensional Array - Fatal编程技术网

Matlab 关于阵列的形状不可知切片

Matlab 关于阵列的形状不可知切片,matlab,multidimensional-array,Matlab,Multidimensional Array,在这篇文章中,我使用术语slice来指n维数组a的子数组bii,这样size(bii,d)对于某些维度d是1A由size(A,d)这样的切片组成,沿维度d连接 例如,如果ndims(A)为6,而d为3,则表单的表达式 A(:, :, i, :, :, :) 对于1中的i:尺寸(A,d)表示构成A的所有切片(沿尺寸d) 像A(:,:,i,:,:,:,:)这样的表达式的问题在于,它不能被符号化地概括为在具有不同于6的维数的数组中沿不同于3的维数切片。例如,要获得沿维度2的A切片,需要一个不同的表达

在这篇文章中,我使用术语slice来指n维数组
a
的子数组
bii
,这样
size(bii,d)
对于某些维度
d
是1
A
size(A,d)
这样的切片组成,沿维度
d
连接

例如,如果
ndims(A)
为6,而
d
为3,则表单的表达式

A(:, :, i, :, :, :)
对于
1中的
i
:尺寸(A,d)
表示构成
A
的所有切片(沿尺寸
d

A(:,:,i,:,:,:,:)
这样的表达式的问题在于,它不能被符号化地概括为在具有不同于6的维数的数组中沿不同于3的维数切片。例如,要获得沿维度2的
A
切片,需要一个不同的表达式,
A(:,i,:,:,:,:)
。这意味着这样的表达式在代码中是无用的,因为代码对要从中提取切片的数组的形状是不可知的

下面的函数是我的MatlabNoob实现形状不可知切片的尝试。(名称
slice
已被采用,因此我将该函数称为
hslice
,是
hyperslice
的缩写)该函数的策略是将输入阵列重塑为合适的三维阵列,沿着重塑后的阵列的第二维度获取所需的切片,并对结果进行整形,使其具有原始输入数组的切片形状

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

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

您可以尝试
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一起去

是的。您可以使用取消引用的单元格数组和“逗号分隔列表”之间的等效性,以及可以使用字符“:”作为索引来动态构造
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;

你为什么认为你的方法没有效率?你试过将它与显式切片进行比较吗?实际上我喜欢你的,因为在切片之前没有数据被重写。@Shai:我主要是希望有一些低级别的内置(可能是非常有效的)函数来实现这一点;另外,由于我不太了解MATLAB中什么是高效的,我的假设是,我的任何实现都可能是低效的(尽管这次我可能很幸运)。在我看来,分析(不仅仅是在MATLAB中)是很棘手的。在这种情况下,我能想到的任何分析方案(如MatlabNoob)都需要将显式切片表达式放入函数中,这可能会显著扭曲比较。嗯,我不相信我能在这方面做任何分析。是的,Matlab性能很难控制,因为操作的成本可能差异很大,所以
O(n)
分析通常不如弄清楚如何使用快速的Matlab内置“矢量化”东西有用。但相对而言,所有这些索引、重塑和复制操作都非常便宜。在函数中执行这项操作很好:因为您要创建一个新数组,所以不可能进行就地优化,而写时拷贝意味着在函数之间传递数组是便宜的。你的方法应该执行得很好。哦,是的-
restrape()
特别快,因为它实际上并没有重新排列内存中的原始原始原始数据:它只是旋转Matlab内部数据结构(“mxArray”)头中的“维度”信息,并保留指向原始底层原始数据的指针。所以这里的实现只不过是对原始数据的一个单一的提取/复制,就像静态的<代码> >(:,,,,,……)/代码>索引表达式。用于两个输入上都有多个成员的较大数据集。它有足够的开销,在这里使用可能会太慢。当其中一个输入为标量或小输入时,
ismember
的情况相同。使用
subdims=1:ndims(ndarray);细分市场(d)=[]
find(x==y)
可能更合适。@AndrewJanke感谢您在这种情况下选择
setdiff
。尽管如此,
permute
可能比
setdiff
慢一个数量级,除非
numel(ndarray)
非常小。这就是为什么我倾向于使用