让numpy.nanargmin在列全为nan时返回nan

6 投票
3 回答
3860 浏览
提问于 2025-04-17 21:46

有没有办法让 numpy.nanargmin 在某一列全是 nan 的情况下返回 numpy.nan 呢?现在如果出现这种情况,它会报 ValueError 错误。而我不能用 numpy.argmin,因为当列里只有几个 nan 时,它也会出错。

http://docs.scipy.org/doc/numpy/reference/generated/numpy.nanargmin.html 里说,当切片全是 nan 时会抛出 ValueError。在这种情况下,我希望它能返回 numpy.nan(这样可以用 nan 来进一步掩盖“非数据”)。

下面这段代码可以做到这一点,但速度非常慢,而且不太符合 Python 的风格:

for i in range(R.shape[0]):
    bestindex = numpy.nanargmin(R[i,:])
    if(numpy.isnan(bestindex)):
        bestepsilons[i]=numpy.nan
    else:
        bestepsilons[i]=epsilon[bestindex]

下面这段代码也可以工作,但前提是没有全是 nan 的列:

ar = numpy.nanargmin(R, axis=1)
bestepsilons = epsilon[ar]

所以理想情况下,我希望最后这段代码也能处理全是 nan 的列。

3 个回答

0

我遇到了一个类似的问题,手里有一个形状为(nz, ny, nx)的数组,其中有些切片[:, j, i]完全是NaN(表示缺失值)。在我的情况下,我需要沿着轴0找到最大值的索引。如果我直接这样做:

np.nanargmax(array,axis=0)

我会得到一个错误:“ValueError: All-NaN slice encountered”(值错误:遇到全是NaN的切片)

因为我对全是NaN的切片不感兴趣,所以我找了个办法,把这些NaN替换成了零。

mask = np.isnan(array)
array[mask] = 0
idx2d = np.argmax(array,axis=0)

这样就可以得到沿着轴0的最大值的索引。然后,idx2d数组可以再进行掩码处理。

idx2d = np.ma.masked_where(mask[0],idx2d)

如果你想找最小值np.argmin,可以用同样的方法,只不过把数组中的NaN替换成一个很大的数字,而不是0。

5
>>> def _nanargmin(arr, axis):
...    try:
...       return np.nanargmin(arr, axis)
...    except ValueError:
...       return np.nan

示例:

>>> a = np.array([[np.nan]*10, np.ones(10)])
>>> _nanargmin(a, axis=1)
nan
>>> _nanargmin(a, axis=0)
array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1])

不过,这可能不是你想要的结果。我不太确定你具体想要什么。如果你只是想过滤掉 nan(表示“不是一个数字”的值),那么可以使用布尔索引来实现:

>>> a[~np.isnan(a)]
array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.])
>>> np.argmin(_)
0

编辑2:看起来你是在寻找掩码数组:

>>> a = np.vstack(([np.nan]*10, np.arange(10), np.arange(11, 1, -1)))
>>> a[2, 4] = np.nan
>>> m = np.ma.masked_array(a, np.isnan(a))
>>> np.argmin(m, axis=0)
array([1, 1, 1, 1, 1, 1, 2, 2, 2, 2])
>>> np.argmin(m, axis=1)
array([0, 0, 9])
3

找到了一个解决办法:

# makes everything nan to start with
bestepsilons1 = numpy.zeros(R.shape[0])+numpy.nan 
# finds the indices where the entire column would be nan, so the nanargmin would raise an error
d0 = numpy.nanmin(R, axis=1) 
# on the indices where we do not have a nan-column, get the right index with nanargmin, and than put the right value in those points
bestepsilons1[~numpy.isnan(d0)] = epsilon[numpy.nanargmin(R[~numpy.isnan(d0),:], axis=1)]

这个方法其实是个变通办法,它只在不会出错的地方使用nanargmin,因为在这些地方我们本来就希望得到的结果是nan的索引。

撰写回答