[英]How can I get the number of indexed elements of array of known shape without actually indexing the array?
I have an index IDX
(which may be either list of indices, boolean mask, tuple of slices etc.) indexing some abstract numpy array of known shape shape
(possibly big).我有一个索引
IDX
(可能是索引列表、boolean 掩码、切片元组等)索引一些已知shape
的抽象 numpy 数组(可能很大)。
I know I can create a dummy array, index it and count the elements:我知道我可以创建一个虚拟数组,对其进行索引并计算元素:
A = np.zeros(shape)
print(A[IDX].size)
Is there any sensible way I can get the number of indexed elements without creating any (potentially big) array?有没有什么明智的方法可以在不创建任何(可能很大)数组的情况下获得索引元素的数量?
I need to tabularize a list of functions at certain points in 3D space.我需要将 3D 空间中某些点的函数列表制成表格。 The points are subset of a rectangular grid given as
X
, Y
, Z
lists and IDX
is indexing their Cartesian product:这些点是作为
X
、 Y
、 Z
列表给出的矩形网格的子集,并且IDX
正在索引它们的笛卡尔积:
XX, YY, ZZ = [A[IDX] for A in np.meshgrid(X, Y, Z)]
The functions accept either X
, Y
, Z
arguments (and return values for their Cartesian product which needs to be indexed) or XX
, YY
, ZZ
.这些函数接受
X
、 Y
、 Z
arguments (并返回需要索引的笛卡尔积的值)或XX
、 YY
、 ZZ
。 At the moment I create XX
, YY
and ZZ
arrays whether they are used or not, then I allocate an array for function values:目前我创建
XX
, YY
和ZZ
arrays 是否使用它们,然后我为 function 值分配一个数组:
self.TAB = np.full((len(functions), XX.size),
np.nan)
but I want to create XX
, YY
and ZZ
only if they are necessary.但我只想在必要时创建
XX
、 YY
和ZZ
。 I also want to separate TAB
allocation from filling its rows, thus I need to know the number of columns in advance.我还想将
TAB
分配与填充其行分开,因此我需要提前知道列数。
Just for fun, let's see if we can make a passable approximation here.只是为了好玩,让我们看看我们是否可以在这里做出一个可以通过的近似值。 Your input can be any of the following:
您的输入可以是以下任何一种:
If the input isn't explicitly a tuple to begin with, make it one.如果输入一开始不是明确的元组,则将其设为一个。 Now you can iterate along the tuple and match it to the shape.
现在您可以沿着元组进行迭代并将其与形状相匹配。 You can't quite zip them together because boolean arrays eat up multiple element of the shape, and trailing axes are included wholesale.
你不能把 zip 放在一起,因为 boolean arrays 会吃掉形状的多个元素,并且尾轴是批发的。
Something like this should do it:这样的事情应该这样做:
def pint(x):
""" Mimic numpy errors """
if isinstance(x, bool):
raise TypeError('an integer is required')
try:
y = int(x)
except TypeError:
raise TypeError('an integer is required')
else:
if y < 0:
raise ValueError('negative dimensions are not allowed')
return y
def estimate_size(shape, index):
# Ensure input is a tuple
if not isinstance(index, tuple):
index = (index,)
# Clean out Nones: they don't change size
index = tuple(i for i in index if i is not None)
# Check shape shape and type
try:
shape = tuple(shape)
except TypeError:
shape = (shape,)
shape = tuple(pint(s) for s in shape)
size = 1
# Check for scalars
if not shape:
if index:
raise IndexError('too many indices for array')
return size
# Process index dimensions
# you could probably use iter(shape) instead of shape[s]
s = 0
# fancy indices need to be gathered together and processed as one
fancy = []
def get(n):
nonlocal s
s += n
if s > len(shape):
raise IndexError('too many indices for array')
return shape[s - n:s]
for ind in index:
if isinstance(ind, slice):
ax, = get(1)
size *= len(range(*ind.indices(ax)))
else:
ind = np.array(ind, ndmin=1, subok=True, copy=False)
if ind.dtype == np.bool_:
# Boolean masking
ax = get(ind.ndim)
if ind.shape != ax:
k = np.not_equal(ind.shape, ax).argmax()
IndexError(f'IndexError: boolean index did not match indexed array along dimension {s - n.ndim + k}; dimension is {shape[s - n.ndim + k]} but corresponding boolean dimension is {ind.shape[k]}')
size *= np.count_nonzero(ind)
elif np.issubdtype(ind.dtype, np.integer):
# Fancy indexing
ax, = get(1)
if ind.min() < -ax or ind.max() >= ax:
k = ind.min() if ind.min() < -ax else ind.max()
raise IndexError(f'index {k} is out of bounds for axis {s} with size {ax}')
fancy.append(ind)
else:
raise IndexError('arrays used as indices must be of integer (or boolean) type')
# Add in trailing dimensions
size *= np.prod(shape[s:])
# Add fancy indices
if fancy:
size *= np.broadcast(*fancy).size
return size
This is only an approximation.这只是一个近似值。 You will need to change it any time the API changes, and it already has some incomplete features.
您需要随时更改 API 更改,并且它已经具有一些不完整的功能。 Testing, fixing and, expanding is left as an exercise for the reader.
测试、修复和扩展留给读者作为练习。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.