2017-01-25 8 views
0

Вот мой вклад:Удаление строки со значениями NaN в recarrays объектного типа данных

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() не работает с типом данных объекта.

+0

Есть 2 проблемы. 'x == np.nan' всегда False. 'nan' не соответствует ничему другому, включая' np.nan'. 'np.isnan' - правильный тест для' nan'. Но он работает только в массиве float 'dtype', а не на объекте или строках. Вам нужно написать функцию, которая условно применяет 'isnan' и не задыхается от строк. Затем примените это итеративно к каждому полю. – hpaulj

+0

Почему ваш массив содержит 'np.nan' вместо строк' nan'? С строковым значением dtype может быть 'U3' (или' S3), и вы можете выполнить 'data ['A']! = 'Nan'' тесты. 'np.nan' - специальное значение float, которое в контексте строк просто дает головные боли. – hpaulj

ответ

0

Определить функцию, которая применяется 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')]) 

==============

Самый простой способ выполнить этот тест removeal над всеми полями, это просто итерацию по именам полей:

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 функция для каждого поля и собраны в массив:

Используйте 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 _ и __ содержат результаты, показанные в предыдущих 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) 

Я никогда не пробовал эту комбинацию tolist и vectorize раньше. Векторизованные функции перебирают свои входы, поэтому они не предлагают много преимуществ по сравнению с явными итерациями, но для таких задач это, безусловно, упрощает кодирование.

Другая возможность - определить 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) 
+0

как я могу отбросить все строки, содержащие NaN за один раз, вместо того, чтобы брать одну переменную за раз? @hpaulj – geedee

+0

Мой тест работает с одним полем одновременно. Мы бы взяли логическую комбинацию между полями: «any (f (A), f (B) и т. Д.)» Или внутри 'foo'. – hpaulj

+0

Я добавил несколько примеров применения этого теста ко всему структурированному массиву. Это проще, чем я думал. – hpaulj