Определить функцию, которая применяется 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)
Есть 2 проблемы. 'x == np.nan' всегда False. 'nan' не соответствует ничему другому, включая' np.nan'. 'np.isnan' - правильный тест для' nan'. Но он работает только в массиве float 'dtype', а не на объекте или строках. Вам нужно написать функцию, которая условно применяет 'isnan' и не задыхается от строк. Затем примените это итеративно к каждому полю. – hpaulj
Почему ваш массив содержит 'np.nan' вместо строк' nan'? С строковым значением dtype может быть 'U3' (или' S3), и вы можете выполнить 'data ['A']! = 'Nan'' тесты. 'np.nan' - специальное значение float, которое в контексте строк просто дает головные боли. – hpaulj