gpt4 book ai didi

python - 为什么在 python 字典中添加多个 'nan' 给出多个条目?

转载 作者:行者123 更新时间:2023-12-04 15:18:44 28 4
gpt4 key购买 nike

示例问题:

import numpy as np
dc = dict()
dc[np.float('nan')] = 100
dc[np.float('nan')] = 200

它正在为 nan 创建多个条目喜欢
dc.keys()将产生 {nan: 100, nan: 200}但它应该创建 {nan: 200} .

最佳答案

对您的问题的简短回答(为什么将 NaN 键添加到 Python dict 会创建多个条目),是因为 浮点 NaN值是无序的 ,即 NaN value 不等于、大于或小于任何东西,包括它自己。此行为在 IEEE 754 中定义浮点运算标准。 IEEE 754 委员会成员 in this answer 解释了为什么会这样.

对于更长的、特定于 Python 的答案,让我们首先看看项目插入和键比较在 CPython 词典中是如何工作的。

当你说 d[key] = val , PyDict_SetItem() 用于字典d被调用,它又调用(内部) insertdict() ,这将更新现有的字典项,或插入一个新项(可能会相应地调整哈希表的大小)。

插入的第一步是查找 key在字典键的哈希表中。在您的情况下(非字符串键)调用的通用查找函数是 lookdict() .
lookdict将使用 key的哈希值来定位 key ,迭代具有相同哈希值的可能键列表,首先按地址进行比较,然后调用 key s 的等价运算符(有关 Objects/dictobject.c 的 Python 实现中散列冲突解决方案的更多详细信息,请参阅 open addressing 中的优秀评论)。

由于每float('nan') 具有相同的哈希值 值,但每一个都是 一个不同的对象 (具有不同的“身份”,即内存地址),它们是 不等于它们的浮点值 :

>>> a, b = float('nan'), float('nan')
>>> hash(a), hash(b)
(0, 0)
>>> id(a), id(b)
(94753433907296, 94753433907272)
>>> a == b
False

当你说:
d = dict()
d[float('nan')] = 1
d[float('nan')] = 2
lookdict将搜索第二个 NaN通过查看它的散列( 0 ),然后尝试通过迭代具有相同散列的键并通过身份/地址(它们不同)比较键来解决散列冲突,然后通过调用(昂贵的) PyObject_RichCompareBool/ do_richcompare ,反过来调用 float_richcompare 就像 C 一样比较浮点数:
/* Comparison is pretty much a nightmare.  When comparing float to float,
* we do it as straightforwardly (and long-windedly) as conceivable, so
* that, e.g., Python x == y delivers the same result as the platform
* C x == y when x and/or y is a NaN.

其行为符合 IEEE 754 标准(来自 GNU C library docs):

20.5.2 Infinity and NaN

[...]

The basic operations and math functions all accept infinity and NaN and produce sensible output. Infinities propagate through calculations as one would expect: for example, 2 + ∞ = ∞, 4/∞ = 0, atan (∞) = π/2. NaN, on the other hand, infects any calculation that involves it. Unless the calculation would produce the same result no matter what real value replaced NaN, the result is NaN.

In comparison operations, positive infinity is larger than all values except itself and NaN, and negative infinity is smaller than all values except itself and NaN. NaN is unordered: it is not equal to, greater than, or less than anything, including itself. x == x is false if the value of x is NaN. You can use this to test whether a value is NaN or not, but the recommended way to test for NaN is with the isnan function (see Floating Point Classes). In addition, <, >, <=, and >= will raise an exception when applied to NaNs.



这将返回 falseNaN == NaN .

这就是为什么 Python 决定第二个 NaN对象值得一个新的字典条目。它可能具有相同的哈希值,但它的地址和等价性测试表明它与所有其他的不同 NaN对象。

但是,请注意,如果您始终使用相同的 NaN对象(具有相同地址),因为在浮点等效之前测试地址, 你会得到预期的行为 :
>>> nan = float('nan')
>>> d = dict()
>>> d[nan] = 1
>>> d[nan] = 2
>>> d
{nan: 2}

关于python - 为什么在 python 字典中添加多个 'nan' 给出多个条目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45300367/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com