【问题标题】:remove entries with nan values in python dictionary删除python字典中具有nan值的条目
【发布时间】:2018-12-04 17:38:26
【问题描述】:

我知道了。 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 都有效,那就太好了

【问题讨论】:

  • 如果你删除.values()它应该可以工作
  • @Aemyl,缺少的{ 是错字,我更正了
  • @Aemyl,删除 .values() 没有帮助。它不会删除有问题的条目
  • 我不得不承认我并没有真正阅读过dict_cg 的定义,并认为它只是一个带有nan 值的字典
  • @RoadRunner,在这种情况下,nan 在字典的值中。并且值是一个元组

标签: python dictionary


【解决方案1】:

由于您有 pandas,因此您可以在此处利用 pandas 的 pd.Series.notnull 函数,该函数适用于混合 dtype。

>>> 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

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]。当您预先转换为系列时,它终于可以工作了:

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

因此,解决方案是对其进行系列化,然后测试这些值。

与此类似,另一个(诚然是迂回的)解决方案是预先转换为 object dtype numpy 数组,pd.notnull 将直接工作:

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

我想pd.notnull 直接把dict_cg[43] 转换成一个字符串数组,把NaN 渲染成字符串“nan”,所以它不再是一个“null”值了。

【讨论】:

  • 感谢@coldspeed!这适用于 python 2 和 3 吗?
  • @user308827 是的。
  • 这是一个干净的答案,虽然原始代码有 Numpy,但没有 Pandas。对于只需要 Numpy 的情况,这有点繁重。
  • @Grismar 我知道你来自哪里,是的,一个干净的答案需要一些牺牲。下面的答案显示了替代方案将是嵌套迭代。
【解决方案2】:

这应该可行:

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))])

【讨论】:

  • 它检查字典中的nan 值和pops 键。
  • 不,它没有。至少,不能保证。
  • 我知道它会起作用的。但不能保证它会起作用。与 nan 进行检查并不总是得到保证,因为比较是在 id 上,而不是在值上。两个 NaN 值不一定必须具有相同的 id。
  • 阅读我上面的评论。我说它会起作用,但不能保证它一直都起作用。我想说的是使用 NaN 进行检查是 bad form
  • @Ash Sharma,您的答案是唯一真正回答用户问题的答案:删除违规条目。人们通常出于某种原因选择 OrderedDict,并且我在处理过程中将 Coldspeed 和我将该 OrderedDict 转换为 dict。顺便说一句,你的缩进是关闭的。
【解决方案3】:

您的原始代码实际上并没有 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周围的条件被评估从左到右。

【讨论】:

  • 请注意,对于 Python 2,您可能需要将 .items() 替换为 .iteritems()
【解决方案4】:

用户308827,

您问题中的代码似乎混淆了键和值,并忽略了您的值是元组的事实。这是一个使用 std 库和在 python 2,3 中工作的 dict 理解的单行:

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))])

【讨论】:

    猜你喜欢
    • 2022-11-25
    • 1970-01-01
    • 2013-12-23
    • 1970-01-01
    • 1970-01-01
    • 2020-09-23
    • 2022-01-23
    • 2010-11-21
    • 1970-01-01
    相关资源
    最近更新 更多