python - 为什么 itertools.groupby 可以将 NaN 分组在列表中而不是在 numpy 数组中

标签 python arrays list numpy nan

我很难调试一个问题,其中 list 中的 float nan 中的 nan numpy.arrayitertools.groupby 中使用时的处理方式不同:

给定以下列表和数组:

from itertools import groupby
import numpy as np

lst = [np.nan, np.nan, np.nan, 0.16, 1, 0.16, 0.9999, 0.0001, 0.16, 0.101, np.nan, 0.16]
arr = np.array(lst)

当我遍历列表时,连续的 nan 被分组:

>>> for key, group in groupby(lst):
...     if np.isnan(key):
...         print(key, list(group), type(key))
nan [nan, nan, nan] <class 'float'>
nan [nan] <class 'float'>

但是,如果我使用数组,它会将连续的 nan 放在不同的组中:

>>> for key, group in groupby(arr):
...     if np.isnan(key):
...         print(key, list(group), type(key))
nan [nan] <class 'numpy.float64'>
nan [nan] <class 'numpy.float64'>
nan [nan] <class 'numpy.float64'>
nan [nan] <class 'numpy.float64'>

即使我将数组转换回列表:

>>> for key, group in groupby(arr.tolist()):
...     if np.isnan(key):
...         print(key, list(group), type(key))
nan [nan] <class 'float'>
nan [nan] <class 'float'>
nan [nan] <class 'float'>
nan [nan] <class 'float'>

我正在使用:

numpy 1.11.3
python 3.5

我知道通常 nan != nan 为什么这些操作会给出不同的结果? groupby 怎么可能对 nan 进行分组?

最佳答案

Python 列表只是指向内存中对象的指针数组。特别是 lst 包含指向对象 np.nan 的指针:

>>> [id(x) for x in lst]
[139832272211880, # nan
 139832272211880, # nan
 139832272211880, # nan
 139832133974296,
 139832270325408,
 139832133974296,
 139832133974464,
 139832133974320,
 139832133974296,
 139832133974440,
 139832272211880, # nan
 139832133974296]

(np.nan 在我的电脑上是 139832272211880。)

另一方面,NumPy 数组只是连续的内存区域;它们是由 NumPy 解释为值序列( float 、整数等)的位和字节区域。

问题在于,当您要求 Python 迭代包含浮点值的 NumPy 数组时(在 for 循环或 groupby 级别),Python 需要将这些值装箱字节转换为适当的 Python 对象。它在迭代时为数组中的每个单个值在内存中创建一个全新的 Python 对象。

例如,您可以看到在调用 .tolist() 时为每个 nan 值创建了不同的对象:

>>> [id(x) for x in arr.tolist()]
[4355054616, # nan
 4355054640, # nan
 4355054664, # nan
 4355054688,
 4355054712,
 4355054736,
 4355054760,
 4355054784,
 4355054808,
 4355054832,
 4355054856, # nan
 4355054880]

itertools.groupby 能够对 Python 列表的 np.nan 进行分组,因为它在比较 Python 对象时首先检查 identity .因为这些指向 nan 的指针都指向同一个 np.nan 对象,所以分组是可能的。

但是,对 NumPy 数组的迭代不允许此初始身份检查成功,因此 Python 回退到检查相等性和 nan != nan 正如您所说。

关于python - 为什么 itertools.groupby 可以将 NaN 分组在列表中而不是在 numpy 数组中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41723419/

相关文章:

python - 用pip安装MySQL-python,得到 "failed with error code 1"

python - 如何将re.findall应用于文件为空列表

java - 从 Java 列表中获取对象

Python itertools.compress 的工作方式与 bool 掩码不同。为什么?

python - 在 Python 中连接两个 32 位 int 以获得 64 位长

C 指针与二维数组

c - K&R 第 2 版,示例 1.9 字符数组

javascript - 带大括号的 If/Else 语句

list - 列表中的下一个元素

python - 如何在python中调用外部程序并检索输出和返回代码?