NumPy数组转换为列表的问题

5
由于某种原因,evalRow(list(array([0, 1, 0, 0, 0])))evalRow([0, 1, 0, 0, 0])的结果不同。然而,如果我使用magicConvert(在这里用于调试)代替list将numpy数组转换为列表,则结果与预期相同:
def magicConvert(a):
  ss = str(list(a))[1:-1]
  return map(int, ss.split(","))

# You don't actually need to read these functions, just here to reproduce the error:
from itertools import *
def evalRow(r):
  grouped = map(
    lambda (v, l): (v, len(tuple(l))),
    groupby(chain([2], r, [2])))
  result = 0
  for player in (1, -1):
    for (pre, mid, post) in allTuples(grouped, 3):
      if mid[0] == player:
        result += player * streakScore(mid[1], (pre[0] == 0) + (post[0] == 0))
  return result

def streakScore(size, blanks):
  return 0 if blanks == 0 else (
    100 ** (size - 1) * (1 if blanks == 1 else 10))

def allTuples(l, size):
  return map(lambda i: l[i : i + size], xrange(len(l) - size + 1))

对我来说,它们给出了相同的结果,即 0... - Saullo G. P. Castro
我认为最好使用 tolist()numpy 数组和列表之间进行转换。使用 list(some_array) 必须遍历 numpy 数组,然后相应地创建列表,而 tolist() 可能可以避免一些通用转换的开销。 - Bakuriu
иҜ·жіЁж„ҸпјҢеҪ“жү§иЎҢ list(array([0, 1, 2])) ж—¶пјҢдјҡеҫ—еҲ°дёҖдёӘеҲ—иЎЁ [0, 1, 2]пјҢе…¶дёӯе…ғзҙ жҳҜ numpy зҡ„ int64 иҖҢдёҚжҳҜ Python зҡ„ intгҖӮдҪҝз”Ё tolist() ж–№жі•еҸҜд»Ҙиҝ”еӣһ Python зҡ„ intгҖӮиҝҷеҸҜиғҪдјҡеҪұе“ҚжӮЁжү§иЎҢзҡ„ж“ҚдҪңе’Ңз»“жһңгҖӮ - Bakuriu
2个回答

9

这种行为的差异是由于执行 list(some_array) 会返回一个由 numpy.int64 组成的列表,而通过字符串表示形式进行转换(或等效地使用 tolist() 方法)则会返回一个由 Python 的 int 组成的列表:

In [21]: import numpy as np

In [22]: ar = np.array([1,2,3])

In [23]: list(ar)
Out[23]: [1, 2, 3]

In [24]: type(list(ar)[0])
Out[24]: numpy.int64

In [25]: type(ar.tolist()[0])
Out[25]: builtins.int

我认为你的代码问题在于100 ** (size - 1)这一部分:
In [26]: 100 ** (np.int64(50) - 1)
Out[26]: 0

In [27]: 100 ** (50 - 1)
Out[27]: 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

In [28]: type(100 ** (np.int64(50) - 1))
Out[28]: numpy.int64

您所看到的是 int64 溢出,因此幂运算的结果实际上是“随机”的,而 Python 的 int 具有无限范围并给出正确的结果。
总结如下:
  • 如果您想在numpy和Python数据类型之间进行转换,请使用适当的方法,在这种情况下使用array.tolist()
  • 请记住,numpy的数据类型具有有限范围,因此在其他情况下应检查溢出并期望奇怪的结果。如果不使用适当的转换方法,则可能会在不希望使用numpy数据类型的情况下使用它们(就像在这种情况下一样)。
  • 永远不要假设这是 Python/numpy/一个非常广泛使用的库中的错误。在这些经过充分测试和广泛使用的软件中找到如此微不足道的错误的机会非常小。如果程序给出意外结果,99.999% 的时间是因为您在做错事情。因此,在责备他人之前,请逐步检查程序正在执行什么操作。

关于你的第三点,我同意在这种情况下这很琐碎,但是在遇到lxml中的几个已知错误后,我对Python变得有些偏执。而且numpy的问题列表看起来至少非常可怕... - OlivierBlanvillain
@OlivierBlanvillain 如果你查看任何严肃的项目问题跟踪器,你会发现成千上万的问题。其中很多只是重复/关闭的。许多是功能请求等,因此实际上作为错误报告的问题数量比人们想象的要小得多。无论如何,没有漏洞是不可能编写任何真正大而复杂的东西的。我的观点是:如果你正在做琐碎的事情,发现漏洞的机会是非常小的。是的,有时候会发生。你应该假设错误在你的代码中,直到你能证明它不是这样。相反的做法需要更长时间来修复。 - Bakuriu

3
我测试了它并得到了不同的结果。不要问我为什么,可能是个 bug 吗?无论如何,总是使用 tolist() 函数将 numpy 数组转换为列表。
evalRow(array([0, 1, 0, 0, 0]).tolist()) == evalRow([0, 1, 0, 0, 0])
#output: True

这仍然没有解释为什么list(.)在这里不起作用,但解决了我的问题 :) - OlivierBlanvillain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接