我正在尝试删除所有前导和尾随的全 NaN 轴(行和列以及它们在 3 维以上的数组中的任何名称)。虽然它对于已知维度来说非常简单,但我想不出使用任意维度数组执行此操作的好方法。
例如
import numpy as np
arr1d = np.array([np.nan, np.nan, np.nan, 1, 2, 3, 4, np.nan])
# expected result: np.array([1., 2., 3., 4.])
arr2d = np.array([[np.nan, np.nan, np.nan],
[1., 2., np.nan],
[4., np.nan, np.nan]])
# expected result: np.array([[1., 2.], [4., np.nan]])
arr3d = np.array([[[np.nan, np.nan, np.nan], [1., np.nan, np.nan], [np.nan, np.nan, np.nan]],
[[np.nan, np.nan, np.nan], [2., np.nan, np.nan], [np.nan, np.nan, np.nan]],
[[np.nan, np.nan, np.nan], [3., np.nan, np.nan], [np.nan, np.nan, np.nan]]])
# expected result: np.array([[[1.]], [[2.]], [[3.]]])
对于一维情况,这很简单:
notnans = np.flatnonzero(~np.isnan(arr1d))
if notnans.size:
trimmed = arr1d[notnans[0]: notnans[-1]+1] # slice from first not-nan to the last one
else:
trimmed = np.zeros(0)
但我正在为多维数组(最好是矢量化)的方法而苦苦挣扎。
请您参考如下方法:
将此问题改写为 “从 bool 的谓词数组中找到用于裁剪前导和尾随 False 的索引”,您可以这样做这通过遍历轴,并使用 any 的多轴形式:
def arg_trim_zeros(pred, axis=None):
"""
Produces an nd slice index that trims zeros from the specified dimensions
"""
# allow multiple axis arguments like other numpy functions
all_axes = tuple(range(pred.ndim))
if axis is None:
axis = all_axes
elif not isinstance(axis, tuple):
axis = (axis,)
slices = [slice(None)] * pred.ndim
# special case if entire input is falsey
if not pred.any():
for ax in axis:
slices[ax] = slice(0, 0)
return slices
# compute slices for each dimension in turn
for ax in axis:
valid = pred.any(axis=all_axes[:ax] + all_axes[ax+1:])
# argmax is safe here, because we're sure there is at least one True in pred
start = valid.argmax()
stop = len(valid) - valid[::-1].argmax()
slices[ax] = slice(start, stop)
return tuple(slices)
所以在你的情况下,这是:
cropped = arr[arg_trim_zeros(~np.isnan(arr))]
它具有返回原始数组副本的好处。
这里并不严格需要 axis 参数,但我想我会添加它来解决更一般的问题。
