numpy是否提供了在对数组进行切片时进行边界检查的方法?例如,如果我执行以下操作:
arr = np.ones([2,2])
sliced_arr = arr[0:5,:]
这个切片是可以的,它会返回整个 arr 数组,即使我请求不存在的索引。有没有其他在 numpy 中切片的方法,如果我尝试切片超出数组边界,就会抛出错误?
np.newaxis
、负步长...),尽管可能还有一些边缘情况失败。import numpy as np
# Wrapping function
def bounds_checked_slice(arr):
return SliceBoundsChecker(arr)
# Wrapper that checks that indexing slices are within bounds of the array
class SliceBoundsChecker:
def __init__(self, arr):
self._arr = np.asarray(arr)
def __getitem__(self, args):
# Slice bounds checking
self._check_slice_bounds(args)
return self._arr.__getitem__(args)
def __setitem__(self, args, value):
# Slice bounds checking
self._check_slice_bounds(args)
return self._arr.__setitem__(args, value)
# Check slices in the arguments are within bounds
def _check_slice_bounds(self, args):
if not isinstance(args, tuple):
args = (args,)
# Iterate through indexing arguments
arr_dim = 0
i_arg = 0
for i_arg, arg in enumerate(args):
if isinstance(arg, slice):
self._check_slice(arg, arr_dim)
arr_dim += 1
elif arg is Ellipsis:
break
elif arg is np.newaxis:
pass
else:
arr_dim += 1
# Go backwards from end after ellipsis if necessary
arr_dim = -1
for arg in args[:i_arg:-1]:
if isinstance(arg, slice):
self._check_slice(arg, arr_dim)
arr_dim -= 1
elif arg is Ellipsis:
raise IndexError("an index can only have a single ellipsis ('...')")
elif arg is np.newaxis:
pass
else:
arr_dim -= 1
# Check a single slice
def _check_slice(self, slice, axis):
size = self._arr.shape[axis]
start = slice.start
stop = slice.stop
step = slice.step if slice.step is not None else 1
if step == 0:
raise ValueError("slice step cannot be zero")
bad_slice = False
if start is not None:
start = start if start >= 0 else start + size
bad_slice |= start < 0 or start >= size
else:
start = 0 if step > 0 else size - 1
if stop is not None:
stop = stop if stop >= 0 else stop + size
bad_slice |= (stop < 0 or stop > size) if step > 0 else (stop < 0 or stop >= size)
else:
stop = size if step > 0 else -1
if bad_slice:
raise IndexError("slice {}:{}:{} is out of bounds for axis {} with size {}".format(
slice.start if slice.start is not None else '',
slice.stop if slice.stop is not None else '',
slice.step if slice.step is not None else '',
axis % self._arr.ndim, size))
import numpy as np
a = np.arange(24).reshape(4, 6)
print(bounds_checked_slice(a)[:2, 1:5])
# [[ 1 2 3 4]
# [ 7 8 9 10]]
bounds_checked_slice(a)[:2, 4:10]
# IndexError: slice 4:10: is out of bounds for axis 1 with size 6
arr[len(arr):]
获取空切片。如果你想要略微不同的行为,原则上你可以编辑代码。range
而不是通常的切片符号,你可以获得预期的行为。例如,对于有效的切片:arr[range(2),:]
array([[1., 1.],
[1., 1.]])
如果我们尝试使用例如以下方式进行切片:
arr[range(5),:]
x = np.arange(25).reshape(5, 5); x[2:4, 2:4]
与 x[range(2, 4), range(2, 4)]
是不同的。 - Prasad Raghavendra
np.any(np.array([i,j]) > arr.shape)
这样的代码可能就可以解决问题。 - Thomas Kühnarr[0:, :]
。如果需要一个错误,则可以将其包装在if arr.shape[0]<5
测试中。 - hpaulj