Numpy 删除对象数据类型的RecArray中具有nan值的行

Numpy 删除对象数据类型的RecArray中具有nan值的行,numpy,nan,recarray,Numpy,Nan,Recarray,以下是我的意见: data = np.array ( [ ( 'a2', 'b1', 'c1' ), ( 'a1', 'b1', 'c1' ), ( 'a2', np.NaN, 'c2' ) ], dtype = [ ( 'A', 'O' ), ( 'B', 'O' ), ( 'C', 'O' ) ] ) . view ( np.recarray) 我希望将此作为输出: rec.array ( [ ( 'a2', 'b1', 'c1' ), ( 'a1', 'b1', 'c1' ) ], dt

以下是我的意见:

data = np.array ( [ ( 'a2', 'b1', 'c1' ), ( 'a1', 'b1', 'c1' ), ( 'a2', np.NaN, 'c2' ) ], dtype = [ ( 'A', 'O' ), ( 'B', 'O' ), ( 'C', 'O' ) ] ) . view ( np.recarray)
我希望将此作为输出:

rec.array ( [ ( 'a2', 'b1', 'c1' ), ( 'a1', 'b1', 'c1' ) ], dtype = [ ( 'A', 'O'), ( 'B', 'O' ), ( 'C', 'O' )  ] )
我试过:

data [ data [ 'B' ] ! = np.NaN ] . view ( np.recarray )
但它不起作用

data [ data [ 'A' ] ! = 'a2' ] . view ( np.recarray ) 
提供所需的输出


为什么此方法不适用于
np.NaN
?如何删除对象数据类型的RecArray中包含
np.NaN
值的行?另外,
~np.isnan()
不适用于对象数据类型。

定义一个应用
np.isnan
,但不会阻塞字符串的函数):

并使用
vectorize
生成一个函数,将其应用于数组的元素,并返回一个布尔数组:

f=np.vectorize(foo, otypes=[bool])
In [441]: np.array([f(data[name]) for name in data.dtype.names])
Out[441]: 
array([[False, False, False, False,  True],
       [False, False,  True, False, False],
       [False, False, False,  True, False]], dtype=bool)
使用您的
数据

In [240]: data = np.array ( [ ( 'a2', 'b1', 'c1' ), ( 'a1', 'b1', 'c1' ), ( 'a2' , np.NaN, 'c2' ) ], dtype = [ ( 'A', 'O' ), ( 'B', 'O' ), ( 'C', 'O' ) ] )
In [241]: data
Out[241]: 
array([('a2', 'b1', 'c1'), ('a1', 'b1', 'c1'), ('a2', nan, 'c2')], 
      dtype=[('A', 'O'), ('B', 'O'), ('C', 'O')])
In [242]: data['B']
Out[242]: array(['b1', 'b1', nan], dtype=object)

In [243]: f(data['B'])
Out[243]: array([False, False,  True], dtype=bool)

In [244]: data[~f(data['B'])]
Out[244]: 
array([('a2', 'b1', 'c1'), ('a1', 'b1', 'c1')], 
      dtype=[('A', 'O'), ('B', 'O'), ('C', 'O')])
==============

在所有字段上执行此测试移除的最简单方法是迭代字段名:

In [429]: data    # expanded with more nan
Out[429]: 
array([('a2', 'b1', 'c1'), ('a1', 'b1', 'c1'), ('a2', nan, 'c2'),
       ('a2', 'b1', nan), (nan, 'b1', 'c1')], 
      dtype=[('A', 'O'), ('B', 'O'), ('C', 'O')])
应用于每个字段并收集到数组中的
f
函数:

In [441]: np.array([f(data[name]) for name in data.dtype.names])
Out[441]: 
array([[False, False, False, False,  True],
       [False, False,  True, False, False],
       [False, False, False,  True, False]], dtype=bool)
使用
any
获取任何项为真的列:

In [442]: np.any(_, axis=0)
Out[442]: array([False, False,  True,  True,  True], dtype=bool)
In [443]: data[_]    # the ones with nan
Out[443]: 
array([('a2', nan, 'c2'), ('a2', 'b1', nan), (nan, 'b1', 'c1')], 
      dtype=[('A', 'O'), ('B', 'O'), ('C', 'O')])
In [444]: data[~__]   # the ones without
Out[444]: 
array([('a2', 'b1', 'c1'), ('a1', 'b1', 'c1')], 
      dtype=[('A', 'O'), ('B', 'O'), ('C', 'O')])
(在Ipython
\uu
\u
中包含前面的
输出
行中显示的结果。)

tolist
将数组转换为元组列表(结构化数组的记录显示为元组):

f
作为一个
矢量化的
函数,能够将
foo
应用于每个元素(显然它确实
np.array(data.tolist(),dtype=object)

我以前从未尝试过将
tolist
vectorize
结合使用。矢量化函数在其输入上进行迭代,因此与显式迭代相比,它们的速度优势不大,但对于这样的任务,它确实简化了编码

另一种可能是定义
foo
以跨记录的字段进行操作。事实上,我在尝试将
f
应用于单个记录时发现了
tolist
技巧:

In [456]: f(data[2])
Out[456]: array(False, dtype=bool)
In [458]: f(list(data[2]))
Out[458]: array([False,  True, False], dtype=bool)
In [459]: f(data[2].tolist())
Out[459]: array([False,  True, False], dtype=bool)

有两个问题
x==np.nan
始终为False
nan
不等于任何其他内容,包括
np.nan
np.isnan
是对
nan
的正确测试。但它只适用于浮点
dtype
数组,而不适用于对象或字符串。您需要编写一个有条件地应用
isnan
且不会阻塞字符串的函数。然后将其迭代应用于每个字段。为什么数组包含
np.nan
而不是
nan
字符串?使用字符串值,数据类型可以是
U3
(或
S3),您可以执行
data['A']!='nan'测试
np.nan
是一个特殊的浮点值,它在字符串上下文中只会让人头疼。如何一次删除包含nan的所有行,而不是一次使用一个变量@hpauljMy测试一次只能处理一个字段。我们需要跨字段进行逻辑组合,
any(f(a)、f(B)等)
或者在
foo
本身中进行逻辑组合。我添加了几个将此测试应用于整个结构化阵列的示例。这比我想象的要容易。
In [449]: f(data.tolist())
Out[449]: 
array([[False, False, False],
       [False, False, False],
       [False,  True, False],
       [False, False,  True],
       [ True, False, False]], dtype=bool)
In [450]: np.any(_, axis=1)
Out[450]: array([False, False,  True,  True,  True], dtype=bool)
In [456]: f(data[2])
Out[456]: array(False, dtype=bool)
In [458]: f(list(data[2]))
Out[458]: array([False,  True, False], dtype=bool)
In [459]: f(data[2].tolist())
Out[459]: array([False,  True, False], dtype=bool)