Skip to main content
 首页 » 编程设计

python之删除多维数组的前导和尾随全纳米轴

2025年05月04日15Leo_wl

我正在尝试删除所有前导和尾随的全 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 参数,但我想我会添加它来解决更一般的问题。