gpt4 book ai didi

python - 为什么 'groupby(x, np.isnan)' 的行为与 'groupby(x) if key is nan' 不同?

转载 作者:行者123 更新时间:2023-11-28 22:31:11 25 4
gpt4 key购买 nike

Since we're on the topic of peculiarities surrounding numpy's nan ,我发现了一些我也不明白的东西。我发布这个问题主要是作为 MSeifert 的扩展,因为看起来我们的两个观察结果可能有一个共同的原因。

早些时候,I posted a solution这涉及在包含 nan 值的序列上使用 itertools.groupby:

return max((sum(1 for _ in group) for key, group in groupby(sequence) if key is nan), default=0)

但是,我看到了this answer关于上面链接的 MSeifert 的问题,该问题显示了我可能制定此算法的另一种方法:

return max((sum(1 for _ in group) for key, group in groupby(sequence, np.isnan)), default=0)

实验

我已经用列表和 numpy 数组测试了这两种变体。代码和结果如下:

from itertools import groupby

from numpy import nan
import numpy as np


def longest_nan_run(sequence):
return max((sum(1 for _ in group) for key, group in groupby(sequence) if key is nan), default=0)


def longest_nan_run_2(sequence):
return max((sum(1 for _ in group) for key, group in groupby(sequence, np.isnan)), default=0)


if __name__ == '__main__':
nan_list = [nan, nan, nan, 0.16, 1, 0.16, 0.9999, 0.0001, 0.16, 0.101, nan, 0.16]
nan_array = np.array(nan_list)

print(longest_nan_run(nan_list)) # 3 - correct
print(longest_nan_run_2(nan_list)) # 7 - incorrect
print(longest_nan_run(nan_array)) # 0 - incorrect
print(longest_nan_run_2(nan_array)) # 7 - incorrect

分析

  • 在所有四种组合中,只有使用原始函数检查列表才能按预期工作。
  • 修改后的函数(使用np.isnan)似乎对列表和数组的工作方式相同
  • 原始 函数在检查数组 时似乎没有找到任何nan 值。

谁能解释这些结果?同样,由于这个问题与 MSeifert 的相关,对他的结果的解释也可能会解释我的结果(反之亦然)。


进一步调查

为了更好地了解正在发生的事情,我尝试打印出 groupby 生成的组:

def longest_nan_run(sequence):
print(list(list(group) for key, group in groupby(sequence) if key is nan))
return max((sum(1 for _ in group) for key, group in groupby(sequence) if key is nan), default=0)


def longest_nan_run_2(sequence):
print(list(list(group) for _, group in groupby(sequence, np.isnan)))
return max((sum(1 for _ in group) for key, group in groupby(sequence, np.isnan)), default=0)

一个根本区别(回想起来是有道理的)是​​原始函数(使用if key is nan)将过滤掉除了 nan 值,因此所有生成的组将仅包含 nan 值,如下所示:

[[nan, nan, nan], [nan]]

另一方面,modified 函数会将所有非nan 值分组到它们自己的组中,如下所示:

[[nan, nan, nan], [0.16, 1.0, 0.16, 0.99990000000000001, 0.0001, 0.16, 0.10100000000000001], [nan], [0.16]]

这解释了为什么修改后的函数在两种情况下都返回 7 - 它将值视为“nan”或“not nan”并且返回最长的连续系列。

这也意味着我对 groupby(sequence, keyfunc) 工作原理的假设是错误的,并且修改后的函数不是原始函数的可行替代方案。

不过,我仍然不确定在列表和数组上运行原始函数时结果的差异。

最佳答案

numpy 数组中的项目访问行为与列表中的不同:

nan_list[0] == nan_list[1]
# False
nan_list[0] is nan_list[1]
# True

nan_array[0] == nan_array[1]
# False
nan_array[0] is nan_array[1]
# False

x = np.array([1])
x[0] == x[0]
# True
x[0] is x[0]
# False

虽然列表包含对同一对象的引用,但 numpy 数组仅“包含”内存区域,并在每次访问元素时即时创建新的 Python 对象。 (感谢 user2357112,指出措辞不准确的地方。)

有道理吧?列表返回相同的对象,数组返回不同的对象 - 显然 groupby 内部使用 is 进行比较......但是等等,没那么容易!为什么 groupby(np.array([1, 1, 1, 2, 3])) 可以正常工作?

答案埋在itertools C source中,第 90 行显示函数 PyObject_RichCompareBool用于比较两个键。

rcmp = PyObject_RichCompareBool(gbo->tgtkey, gbo->currkey, Py_EQ);

虽然这基本上等同于在 Python 中使用 ==,但文档指出了一个特殊性:

Note If o1 and o2 are the same object, PyObject_RichCompareBool() will always return 1 for Py_EQ and 0 for Py_NE.

这意味着实际上执行了这个比较(等效代码):

if o1 is o2:
return True
else:
return o1 == o2

因此对于列表,我们有相同的 nan 对象,它们被标识为相等。相反,数组为我们提供了具有值 nan 的不同对象,这些对象与 == 进行比较 - 但 nan == nan 始终评估为 错误

关于python - 为什么 'groupby(x, np.isnan)' 的行为与 'groupby(x) if key is nan' 不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41724037/

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