0

这是我的输入:

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?如何删除包含np.NaN对象数据类型的重新数组中的值的行?此外,~np.isnan()不适用于对象数据类型。

4

1 回答 1

1

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

def foo(item):
    try:
        return np.isnan(item)
    except TypeError:
        return False

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

f=np.vectorize(foo, otypes=[bool])

用你的data

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获取任何项目为 True 的列:

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 中___包含前几Out行中显示的结果。)

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

In [448]: data.tolist()
Out[448]: 
[('a2', 'b1', 'c1'),
 ('a1', 'b1', 'c1'),
 ('a2', nan, 'c2'),
 ('a2', 'b1', nan),
 (nan, 'b1', 'c1')]

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

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)

我从来没有尝试过这种tolistvectorize之前的组合。矢量化函数迭代其输入,因此与显式迭代相比,它们并没有提供太多的速度优势,但对于这样的任务,它确实简化了编码。

另一种可能性是定义foo跨记录的字段进行操作。事实上,tolist当我尝试应用f到单个记录时,我发现了诀窍:

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)
于 2017-01-25T05:59:56.727 回答