切片slice(start, stop[, step])
的索引通常可以用range(start, stop, step)
表示(如果考虑到底层维度,则可以用range(*slice(start, stop, step).indices(length))
表示)。
假设我有两个多维切片,第二个切片可以用作应用第一个切片的结果的切片。
示例:
import numpy as np
data = np.random.rand(*(100, 100, 100))
a = data[::2, 7, :] # slice 1, a.shape = (50,100)
b = a[1, ::-1] # slice 2, b.shape = (100,)
我想找到一个通用的表达式来计算做同样工作的单个切片。我知道底层数据结构的维度。
c = data[2, 7, ::-1] # same as b
np.array_equal(b, c) # True
因此,在本例中从[::2, 7, :]
和[1, ::-1]
转到[2, 7, ::-1]
时,我需要一个如下所示的函数:
def concatenate_slices(shape, outer_slice, inner_slice):
...
return combined_slice
其中outer_slice
和inner_slice
都是切片的元组。在示例shape=(100, 100, 100)
和outer_slice=(slice(None, None, 2), 7, slice(None, None, None))
以及inner_slice=(1, slice(None, None, -1))
中。
我不确定如何有效地做到这一点。
当__getitem__(slice)
被调用时,我的对象会做一些事情(没有中间视图),我只想做一次,但仍然有可能有切片。
作为一个扩展(可选),我想知道如果在切片中有省略号会发生什么。那么我怎样才能做出组合呢?
发布于 2015-12-22 01:25:29
让我们从一个简单的例子开始:一维阵列。我们需要跟踪最终切片的start
、stop
和step
值,我们可以像这样更新这些值:
def update_1d(a, b, length):
a_start, a_stop, a_step = a.indices(length)
a_length = len(xrange(a_start, a_stop, a_step))
if a_length == 0:
# doesn't matter what b is if data[a] is []
return a
b_start, b_stop, b_step = b.indices(a_length)
b_length = len(xrange(b_start, b_stop, b_step))
if b_length == 0:
# result will be empty, so we can exit early
return slice(0, 0, 1)
# convert b's start into a's coordinates, without wrapping around
start = max(0, a_start + b_start * a_step)
# steps are multiplicative, which makes things easy
step = a_step * b_step
# the stop index is the hard part because it depends on the sign of both steps
x = a_start + b_stop * a_step
if step < 0:
# indexing backwards, so truncate if b's converted step goes below zero
stop = x if x >= 0 else None
elif a_step > 0:
# both steps are positive, so take the smallest stop index
stop = min(a_stop, x)
else:
# both steps are negative, so take the largest stop index
stop = max(a_stop, x)
return slice(start, stop, step)
请注意,这需要a
和b
是切片。不过,您通常可以将其他表单转换为切片对象。这甚至包括Ellipsis
对象,假设您知道自己有多少维。
为了将其扩展到多维情况,我们需要做一些记账工作,以跟踪原始维度被切片的情况。例如,如果使用data[::2, 7, :][:, 2:-2]
,则必须将第二个切片的第二个维度映射到第一个切片的第三个维度。
发布于 2015-12-22 01:56:39
我怀疑你只需要经历分析每个维度的单调乏味的工作,就可以建立一个新的切片或一组索引。我怀疑有没有捷径。
为了进行说明,以您的示例为例:
In [77]: shape=(100,100,100)
In [78]: outer_slice=(slice(None, None, 2), 7, slice(None, None, None))
In [79]: inner_slice=(1, slice(None, None, -1))
目标是(对吗?):
(2, 7, slice(None,None,-1))
第一维-生成整个索引范围的数组,并按顺序对它们进行切片:
In [80]: idx=np.arange(shape[0])
In [81]: idx[outer_slice[0]][inner_slice[0]]
Out[81]: 2
我可以从::2和1中推导出来吗?我必须推断它从0开始,形状足够大,可以产生第二个值,等等
现在是二维图。这是一个标量,所以没有对应的inner
切片。
In [82]: outer_slice[1]
Out[82]: 7
对于第三个,让我们和第一个一样,但是要考虑到外部和内部列表之间的偏移量:
In [83]: idx=np.arange(shape[2])
In [84]: idx[outer_slice[2]][inner_slice[1]]
Out[84]:
array([99, 98, 97, 96, 95, 94, 93, 92, 91, ....7, 6, 5, 4, 3, 2, 1, 0])
或者我可以推断outer_slice[2]
什么也不做,所以我可以直接使用inner_slice[1]
。
当然,将两个切片元组应用于实际数组也同样简单和高效。
X[outer_slice][inner_slice]
只要outer_slice
生成一个视图,将它们组合成一个复合切片并没有太大的改进。
有了形状和切片元组,就有了足够的信息来构建新的元组。但似乎所需的逻辑将相当复杂,并且需要深入的切片知识和大量的测试。
https://stackoverflow.com/questions/34395403
复制相似问题