удалить записи со значениями nan в словаре Python - PullRequest
0 голосов
/ 26 июня 2018

У меня есть следующие.словарь в Python:

OrderedDict([(30, ('A1', 55.0)), (31, ('A2', 125.0)), (32, ('A3', 180.0)), (43, ('A4', nan))])

Есть ли способ удалить записи, где любое из значений является NaN?Я попробовал это:

{k: dict_cg[k] for k in dict_cg.values() if not np.isnan(k)}

Было бы замечательно, если soln работает как для Python 2 и Python 3

Ответы [ 4 ]

0 голосов
/ 26 июня 2018

user308827,

Код в вашем вопросе, кажется, путает ключи и значения и игнорирует тот факт, что ваши значения являются кортежами.Вот один вкладыш, использующий std libs и понимание dict, которое работает в python 2,3:

from collections import OrderedDict
import math

od = OrderedDict([(30, ('A1', 55.0)), (31, ('A2', 125.0)), (32, ('A3', 180.0)), (43, ('A4', float('Nan')))])

no_nans = OrderedDict({k:v for k, v in od.items() if not math.isnan(v[1])})
# OrderedDict([(30, ('A1', 55.0)), (31, ('A2', 125.0)), (32, ('A3', 180.0))])
0 голосов
/ 26 июня 2018

Это должно работать:

for k,v in dict_cg.items():
    if np.isnan(v[1]):
       dict_cg.pop(k)
print dict_cg

Вывод:

OrderedDict([(30, ('A1', 55.0)), (31, ('A2', 125.0)), (32, ('A3', 180.0))])
0 голосов
/ 26 июня 2018

Ваш исходный код на самом деле не имел pandas, и импорт его только для фильтрации по NaN кажется чрезмерным.Тем не менее, ваш код использовал numpy (np).

Предполагается, что ваша первая строка должна читать:

dict_cg = OrderedDict([(30, ('A1', 55.0)), (31, ('A2', 125.0)), (32, ('A3', 180.0)), (43, ('A4', np.nan))])

Эта строка близка к тому, что у вас было и работает, хотя итребует, чтобы вы импортировали библиотеку по умолчанию numbers:

OrderedDict([(k, vs) for k, vs in d.items() if not any ([isinstance(v, numbers.Number) and np.isnan(v) for v in vs])])

Таким образом, вам не нужно pandas, ваш результат по-прежнему OrderedDict (как и раньше) и вы не сталкиваетесь спроблемы со строками в кортежах, поскольку условия вокруг and оцениваются слева направо.

0 голосов
/ 26 июня 2018

Поскольку у вас есть панды, вы можете использовать здесь функцию pd.Series.notnull панд, которая работает со смешанными типами.

>>> import pandas as pd
>>> {k: v for k, v in dict_cg.items() if pd.Series(v).notna().all()}
{30: ('A1', 55.0), 31: ('A2', 125.0), 32: ('A3', 180.0)}

Это не часть ответа, но может помочь вам понятькак я пришел к решению.Я столкнулся со странным поведением, пытаясь решить этот вопрос, используя pd.notnull напрямую.

Take dict_cg[43].

>>> dict_cg[43]
('A4', nan)

pd.notnull не работает.

>>> pd.notnull(dict_cg[43])
True

Он рассматривает кортеж как одно значение (а не итеративное из значений).Кроме того, преобразование этого в список и последующее тестирование также дает неправильный ответ.

>>> pd.notnull(list(dict_cg[43]))
array([ True,  True])

Поскольку второе значение равно nan, результат, который я ищу, должен быть [True, False].Наконец, это работает, когда вы предварительно преобразуете в Series:

>>> pd.Series(dict_cg[43]).notnull() 
0     True
1    False
dtype: bool

Итак, решение состоит в том, чтобы Series-ify его, а затем проверить значения.

Аналогичным образом, другое (заведомо обходное) решение заключается в предварительном преобразовании в массив numpy object dtype, и pd.notnull будет работать напрямую:

>>> pd.notnull(np.array(dict_cg[43], dtype=object))
Out[151]: array([True,  False])

Я думаю, чтоpd.notnull непосредственно преобразует dict_cg[43] в строковый массив под обложками, отображая NaN в виде строки "nan", поэтому оно больше не является "нулевым" значением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...