如何从NumPy数组中删除NaN值?

359

如何从NumPy数组中删除NaN值?

[1, 2, NaN, 4, NaN, 8]   ⟶   [1, 2, 4, 8]
13个回答

577

从NumPy数组x中删除NaN值:

x = x[~numpy.isnan(x)]
解释

内部函数numpy.isnan返回一个布尔/逻辑数组,其中每个值为True表示对应的x不是数字。由于我们想要相反的结果,因此我们使用逻辑非运算符~获取一个数组,其中每个值为True表示对应的x是有效的数字。

最后,我们使用这个逻辑数组来索引原始数组x,以仅检索非NaN值。


51
x 中所有的非有限数值去除,并重新赋值给 x。可以用以下代码实现:x = x[numpy.isfinite(x)] - Miki Tebeka
23
或者使用x = x[~numpy.isnan(x)],这与mutzmatron的原始回答是等效的,但更短。如果你想保留无穷大的值,应该知道numpy.isfinite(numpy.inf) == False,当然,~numpy.isnan(numpy.inf) == True - chbrown
17
对于希望使用ndarray并保持维度的人,可以使用numpy where函数:np.where(np.isfinite(x), x, 0) - BoltzmannBrain
1
类型错误:只有整数标量数组可以转换为标量索引。 - towry
1
@towry:这是因为你的输入 x 不是一个 numpy 数组。如果你想使用逻辑索引,它必须是一个数组 - 例如 x = np.array(x) - jmetz
显示剩余6条评论

76
filter(lambda v: v==v, x)

该函数适用于列表和numpy数组,因为v!= v仅适用于NaN。


12
这是一个简单但特别实用的技巧,适用于从对象数组中过滤出混合类型(例如包含字符串和NaN值)的数据时使用。 - Austin Richardson
5
这可能看起来很聪明,但会掩盖逻辑,理论上其他对象(如自定义类)也可以拥有这个属性。 - Chris_Rands
1
x[~numpy.isnan(x)] 相比,它可能会慢些。 - smm
同样地,作为列表推导式,例如 [v for v in var if v == v] - Darren Weber
什么是v,什么是x? - M_Idk392845
显示剩余2条评论

43

对我来说,@jmetz的答案不起作用,但使用pandas的isnull()函数解决了问题。

x = x[~pd.isnull(x)]

2
or: x = x[x.notnull()] - kbridge4096
我不喜欢在管道中包含熊猫,但是接受的解决方案给了我一个TypeError: ufunc 'isnan' not supported for the input types错误。它不能处理字符串或对象类型。而这个解决方案可以。 - Llohann

36

试试这个:

import math
print [value for value in x if not math.isnan(value)]

想要了解更多,请阅读列表推导式


5
如果你正在使用numpy,那么我和@lazy1的答案都比列表推导式快近一个数量级,其中lazy1的解决方案略微更快(尽管从技术上讲也不会返回任何无穷大的值)。 - jmetz
不要忘记括号 :) print([value for value in x if not math.isnan(value)]) - hypers
如果您像顶部答案一样使用numpy,则可以使用np包中的列表推导式回答:因此,返回不带nans的列表:[value for value in x if not np.isnan(value)] - yeliabsalohcin

20

@jmetz的答案可能是大多数人需要的答案;然而它产生了一个一维数组,使得它无法用于在矩阵中删除整行或整列。

为了这样做,应该将逻辑数组减少为一维,然后对目标数组进行索引。例如,以下操作将删除至少有一个NaN值的行:

x = x[~numpy.isnan(x).any(axis=1)]

点击此处查看更多详细信息。


8

正如其他人所展示的那样

x[~numpy.isnan(x)]

它可以工作。但是,如果numpy的dtype不是本地数据类型(例如,如果它是对象),它将抛出一个错误。在这种情况下,您可以使用pandas。

x[~pandas.isna(x)] or x[~pandas.isnull(x)]

7
如果您正在使用numpy
# first get the indices where the values are finite
ii = np.isfinite(x)

# second get the values
x = x[ii]

7
这篇文章介绍了一种使用 Pandas 的 dropna() 功能来解决问题的方法,适用于一维和二维数组。在二维情况下,你可以选择删除包含 np.nan行或列。其中,被接受的答案 是针对二维数组的形状变换的。
import pandas as pd
import numpy as np

def dropna(arr, *args, **kwarg):
    assert isinstance(arr, np.ndarray)
    dropped=pd.DataFrame(arr).dropna(*args, **kwarg).values
    if arr.ndim==1:
        dropped=dropped.flatten()
    return dropped

x = np.array([1400, 1500, 1600, np.nan, np.nan, np.nan ,1700])
y = np.array([[1400, 1500, 1600], [np.nan, 0, np.nan] ,[1700,1800,np.nan]] )


print('='*20+' 1D Case: ' +'='*20+'\nInput:\n',x,sep='')
print('\ndropna:\n',dropna(x),sep='')

print('\n\n'+'='*20+' 2D Case: ' +'='*20+'\nInput:\n',y,sep='')
print('\ndropna (rows):\n',dropna(y),sep='')
print('\ndropna (columns):\n',dropna(y,axis=1),sep='')

print('\n\n'+'='*20+' x[np.logical_not(np.isnan(x))] for 2D: ' +'='*20+'\nInput:\n',y,sep='')
print('\ndropna:\n',x[np.logical_not(np.isnan(x))],sep='')

Result:

==================== 1D Case: ====================
Input:
[1400. 1500. 1600.   nan   nan   nan 1700.]

dropna:
[1400. 1500. 1600. 1700.]


==================== 2D Case: ====================
Input:
[[1400. 1500. 1600.]
 [  nan    0.   nan]
 [1700. 1800.   nan]]

dropna (rows):
[[1400. 1500. 1600.]]

dropna (columns):
[[1500.]
 [   0.]
 [1800.]]


==================== x[np.logical_not(np.isnan(x))] for 2D: ====================
Input:
[[1400. 1500. 1600.]
 [  nan    0.   nan]
 [1700. 1800.   nan]]

dropna:
[1400. 1500. 1600. 1700.]

7

如果有所帮助的话,对于简单的一维数组:

x = np.array([np.nan, 1, 2, 3, 4])

x[~np.isnan(x)]
>>> array([1., 2., 3., 4.])

但如果你希望扩展到矩阵并保留形状:

x = np.array([
    [np.nan, np.nan],
    [np.nan, 0],
    [1, 2],
    [3, 4]
])

x[~np.isnan(x).any(axis=1)]
>>> array([[1., 2.],
           [3., 4.]])

在处理pandas的.shift()功能时,我遇到了这个问题,并且我想尽一切办法避免使用.apply(..., axis=1),因为它效率低下。


6
完成上述操作:
x = x[~numpy.isnan(x)]

或者

x = x[numpy.logical_not(numpy.isnan(x))]

我发现将同一变量(x)重置并不能移除实际的nan值,必须使用不同的变量。将其设置为不同的变量可以移除nan。

例如:
y = x[~numpy.isnan(x)]

这很奇怪;根据文档,布尔数组索引(也就是这种情况)属于高级索引,而且显然"始终返回数据的副本",所以你应该使用新值覆盖x(即不带NaN的值...)。您能否提供更多信息,以说明可能发生了什么? - jmetz

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