获取排序numpy矩阵或pandas数据框的最后一个非nan索引

5

给定一个类似于这样的numpy数组(或pandas数据帧):

import numpy as np

a = np.array([
[1,      1,      1,    0.5, np.nan, np.nan, np.nan],
[1,      1,      1, np.nan, np.nan, np.nan, np.nan],
[1,      1,      1,    0.5,   0.25,  0.125,  0.075],
[1,      1,      1,   0.25, np.nan, np.nan, np.nan],
[1, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],
[1,      1,    0.5,    0.5, np.nan, np.nan, np.nan]
])

我希望能够高效地检索每行中最后一个非NaN值,因此在这种情况下,我需要寻找一个返回类似于以下内容的函数:

np.array([3,
          2,
          6,
          3,
          0,
          3])

我可以尝试使用np.argmin(a, axis=1) - 1,但这种方法至少有两个缺点-对于不以nan结尾的行无法处理(不能接受),而且它不是"惰性评估",只要到达给定行中的最后一个非nan值就会停止(这一点没有“必须正确”的条件那么重要)。
我想用np.where应该也可以实现,但是除了要评估每行所有元素之外,我无法看出明显的优雅方法来重新排列输出,以获取每行中的最后一个索引。
>>> np.where(np.isnan(a))
(array([0, 0, 0, 1, 1, 1, 1, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5]),
 array([4, 5, 6, 3, 4, 5, 6, 4, 5, 6, 1, 2, 3, 4, 5, 6, 4, 5, 6]))
5个回答

7

这个解决方案不需要对数组进行排序。它只返回沿轴1的最后一个非nan项。

(~np.isnan(a)).cumsum(1).argmax(1)

4

pandas.Series有一个 last_valid_index 方法:

pd.DataFrame(a.T).apply(pd.Series.last_valid_index)
Out: 
0    3
1    2
2    6
3    3
4    0
5    3
dtype: int64

4

检查是否不为NaN,然后反转列的顺序并取argmax,最后从列数中减去结果。

a.shape[1] - (~np.isnan(a))[:, ::-1].argmax(1) - 1

array([3, 2, 6, 3, 0, 3])

last_valid_index的实现与这个非常相似。我尝试过适应,但失败了。 - ayhan

3
如果所有的nan值都已经被排序到每行的末尾,你可以像这样操作:
(~np.isnan(a)).sum(axis = 1) - 1
# array([3, 2, 6, 3, 0, 3])

1

这里有一种方法可以实现,可能不是最高效的:

list(map(lambda x: [i for i, x_ in enumerate(x) if not np.isnan(x_)][-1], a))

此外,如果任何一行完全为 'nan',它也会失败,因为Python将尝试在空列表上执行 getitem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接