Python';s和Numpy';s nan和set
我在Python的Numpy、set和NaN(非数字)中遇到了一种不可预测的行为: 这里np.nan生成一个元素集,而Numpy的nan在一个集中生成多个nan。浮动('nan')也是如此!请注意:Python';s和Numpy';s nan和set,python,numpy,set,nan,Python,Numpy,Set,Nan,我在Python的Numpy、set和NaN(非数字)中遇到了一种不可预测的行为: 这里np.nan生成一个元素集,而Numpy的nan在一个集中生成多个nan。浮动('nan')也是如此!请注意: >>> type(float('nan')) == type(np.nan) True 我想知道这种差异是如何产生的,以及不同行为背后的合理性是什么。NAN的特性之一就是NAN!=南,不像其他数字。但是,set的实现首先检查id(x)是否与哈希索引中的现有成员匹配,然后再尝试插入
>>> type(float('nan')) == type(np.nan)
True
我想知道这种差异是如何产生的,以及不同行为背后的合理性是什么。NAN的特性之一就是NAN!=南,不像其他数字。但是,
set
的实现首先检查id(x)是否与哈希索引中的现有成员匹配,然后再尝试插入新成员。如果有两个ID不同的对象都具有NAN值,那么在集合中会有两个条目。如果它们都有相同的id,则会折叠成一个条目
正如其他人所指出的,
np.nan
是一个始终具有相同id的单一对象。它看起来像numpy.nan
是一个单一对象。因此,它的每个实例都具有相同的标识。查看id(np.nan)'v
id(np.float64('nan'))`(对于重复实例)。[id(np.float64('nan')表示范围(10)中的n]
给出[65159576、65159576、65159576、65159576、65159576、65159576、65159576、65159576、65159576、65159576]和[id(np.nan)表示范围(10)]
给出了[35133032、35133032、35133032、35133032、35133032、35133032、35133032、35133032、35133032、35133032]
@FinnÅrupNielsen在这种情况下创建的NAN对象每次都会被销毁,因为它是没有引用的临时对象,并且对象位置正在被重用。这就是为什么每次都会得到相同的id。@FinnÅrupNielsen对于我来说,numpy 1.8.0的结果不同,[id(np.float64('nan'))是两个不同的id,用于范围(10)内的n]
。这是因为我们正在丢弃对象,因此CPython可以重用内存空间。尝试使用:x=[np.float64('nan'),表示范围(10)中的n);[id(y)表示x中的y]
关于“始终具有相同的id”,有些事情是奇怪的:如果l=np.array([np.nan,np.nan])
,那么id(l[0])、id(l[1])、[id(x)表示l中的x]
是(946651263888946651263888、[946651263888、[946651263912])
@fuglede这是一个很棒的评论!“有人知道为什么会这样吗?”episodeyang问得好。我希望x的是一致的,要么给出实际对象的引用,要么制作副本。它似乎有一些我还没有弄明白的微妙之处。还要注意的是,不能保证后续调用id(l[0])
会给出相同的结果,如果您使用list(map(id,l))
而不是理解,您会得到重复的id(但是list(map(id,list(l))
确实创建了一个副本); 阵列很有趣。这种行为并不特定于np.nan
;比如说,整数也是一样的。整数的例子本身也很有趣,因为当使用低整数时,你得到的对象不一定是CPython维护的单例;比较np.array([2,2])中x的[id(x)]
和[2,2]]中x的[id(x)]
。因此,所有这一切实际上更多地说明了数组的行为,但它确实表明,您不能总是假设两个看起来都像np.nan
的对象必然具有相同的id
。特别是,在原始文章中提供的示例中,set(np.array([np.nan,np.nan])
将给出一个两元素集。
>>> type(float('nan')) == type(np.nan)
True