在pandas数据框中查找具有NaN值的行的整数索引

126

我有一个像这样的pandas DataFrame:

                    a         b
2011-01-01 00:00:00 1.883381  -0.416629
2011-01-01 01:00:00 0.149948  -1.782170
2011-01-01 02:00:00 -0.407604 0.314168
2011-01-01 03:00:00 1.452354  NaN
2011-01-01 04:00:00 -1.224869 -0.947457
2011-01-01 05:00:00 0.498326  0.070416
2011-01-01 06:00:00 0.401665  NaN
2011-01-01 07:00:00 -0.019766 0.533641
2011-01-01 08:00:00 -1.101303 -1.408561
2011-01-01 09:00:00 1.671795  -0.764629

有没有一种有效的方法来找到具有NaN值的行的“整数”索引?在这种情况下,期望的输出应该是[3, 6]


15
如果您只想选择具有NaN值的行,可以使用df[np.isnan(df['b'])] - Miki Tebeka
4
回复@lazy1的问题 - 你可以使用df['b'].isnull()代替使用numpyisnan函数。 - jmetz
16个回答

159

这里有一个更简单的解决方案:

inds = pd.isnull(df).any(1).nonzero()[0]

In [9]: df
Out[9]: 
          0         1
0  0.450319  0.062595
1 -0.673058  0.156073
2 -0.871179 -0.118575
3  0.594188       NaN
4 -1.017903 -0.484744
5  0.860375  0.239265
6 -0.640070       NaN
7 -0.535802  1.632932
8  0.876523 -0.153634
9 -0.686914  0.131185

In [10]: pd.isnull(df).any(1).nonzero()[0]
Out[10]: array([3, 6])

35
我使用了这个:np.where(df['b'].notnull())[0] - user1642513
8
你可以进一步简化这个代码:r, _ = np.where(df.isna()) - cs95
6
请添加 .to_numpy() 将数据转换为NumPy数组 - pd.isnull(df).any(1).to_numpy().nonzero() - 7bStan
6
属性错误:'Series'对象没有'nonzero'属性。 - huang
1
从pandas版本0.25开始,使用pd.isnull(df).any(1).to_numpy().nonzero(),正如7bStan所提到的。这将解决Joe Huang的问题。 - wueb
显示剩余2条评论

55

对于 DataFrame df

import numpy as np
index = df['b'].index[df['b'].apply(np.isnan)]

将会返回MultiIndex,您可以使用它来对df进行索引,例如:

df['a'].ix[index[0]]
>>> 1.452354

对于整数索引:

df_index = df.index.values.tolist()
[df_index.index(i) for i in index]
>>> [3, 6]

1
尽管ix听起来很直观,但由于某些原因,它似乎已经被弃用,而iloc则更受青睐。 - cardamom

28

一行解决方案。但是它只适用于单列。

df.loc[pandas.isna(df["b"]), :].index

这就是我一直在寻找的。我通过将其包装在list(...)中,将其转换为列表,就像这样:list(df.loc[pandas.isna(df["b"]), :].index) - Daniel Butler

12

如果您想找到所有列中“NaN”的坐标(假设它们全部是数字),请使用以下代码:

df = pd.DataFrame([[0,1,3,4,np.nan,2],[3,5,6,np.nan,3,3]])

df
   0  1  2    3    4  5
0  0  1  3  4.0  NaN  2
1  3  5  6  NaN  3.0  3

np.where(np.asanyarray(np.isnan(df)))
(array([0, 1]), array([4, 3]))

11

我不知道现在是否已经太晚,但是你可以使用 np.where 查找非值的索引,如下所示:

indices = list(np.where(df['b'].isna()[0]))

6

如果您拥有日期时间索引,并且想要获得值:

df.loc[pd.isnull(df).any(1), :].index.values

5
这里有几种方法的测试结果:
%timeit np.where(np.isnan(df['b']))[0]
%timeit pd.isnull(df['b']).nonzero()[0]
%timeit np.where(df['b'].isna())[0]
%timeit df.loc[pd.isna(df['b']), :].index

它们的对应时间如下:

333 µs ± 9.95 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
280 µs ± 220 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
313 µs ± 128 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
6.84 ms ± 1.59 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

似乎 pd.isnull(df['DRGWeight']).nonzero()[0] 在计时方面表现最佳,但前三种方法的性能相当。


3
这将为您提供每列中NaN的索引值:
df.loc[pd.isna(df).any(1), :].index

这将创建一个新的数据框,其中包含所有行都包含NaN值,然后返回其索引。 - Nixon Kosgei

3
另一个简单的解决方案是 list(np.where(df['b'].isnull())[0])。这与检查 b 列是否为空值,然后返回其索引相同。

1
这是另一种更简单的方法:
df = pd.DataFrame([[0,1,3,4,np.nan,2],[3,5,6,np.nan,3,3]])

inds = np.asarray(df.isnull()).nonzero()

(array([0, 1], dtype=int64), array([4, 3], dtype=int64))

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