伙计们,
是否存在Numpy与python不同的陷阱集合,这些点令人困惑且花费时间?
"那一刻我永远不会忘记的恐怖!"
"不过,你会这样说的,"女王说,"如果你不做备忘录的话."
例如,NaN在任何地方总是麻烦.如果您可以在不运行的情况下解释这一点,请给自己一点 -
from numpy import array, NaN, isnan
pynan = float("nan")
print pynan is pynan, pynan is NaN, NaN is NaN
a = (0, pynan)
print a, a[1] is pynan, any([aa is pynan for aa in a])
a = array(( 0, NaN ))
print a, a[1] is NaN, isnan( a[1] )
Run Code Online (Sandbox Code Playgroud)
(我不是那么笨拙,在那里做了很多好工作,只是认为常见问题解答或问题的维基会很有用.)
编辑:我希望收集六个陷阱(人们学习Numpy的惊喜).
然后,如果有共同的问题或更好的常见解释,我们可以谈谈将它们添加到社区Wiki(在哪里?)看起来我们到目前为止还不够.
小智 24
因为__eq__不返回bool,所以在任何类型的容器中使用numpy数组都会阻止在没有特定于容器的工作的情况下进行相等性测试.
例:
>>> import numpy
>>> a = numpy.array(range(3))
>>> b = numpy.array(range(3))
>>> a == b
array([ True, True, True], dtype=bool)
>>> x = (a, 'banana')
>>> y = (b, 'banana')
>>> x == y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Run Code Online (Sandbox Code Playgroud)
这是一个可怕的问题.例如,您不能为使用的容器编写单元测试,TestCase.assertEqual()而必须编写自定义比较函数.假设我们编写了一个解决方法special_eq_for_numpy_and_tuples.现在我们可以在unittest中做到这一点:
x = (array1, 'deserialized')
y = (array2, 'deserialized')
self.failUnless( special_eq_for_numpy_and_tuples(x, y) )
Run Code Online (Sandbox Code Playgroud)
现在我们必须为我们可能用来存储numpy数组的每个容器类型执行此操作.此外,__eq__可能会返回bool而不是bool数组:
>>> a = numpy.array(range(3))
>>> b = numpy.array(range(5))
>>> a == b
False
Run Code Online (Sandbox Code Playgroud)
现在,我们每个特定于容器的相等比较函数也必须处理这种特殊情况.
也许我们可以用子类修补这个疣?
>>> class SaneEqualityArray (numpy.ndarray):
... def __eq__(self, other):
... return isinstance(other, SaneEqualityArray) and self.shape == other.shape and (numpy.ndarray.__eq__(self, other)).all()
...
>>> a = SaneEqualityArray( (2, 3) )
>>> a.fill(7)
>>> b = SaneEqualityArray( (2, 3) )
>>> b.fill(7)
>>> a == b
True
>>> x = (a, 'banana')
>>> y = (b, 'banana')
>>> x == y
True
>>> c = SaneEqualityArray( (7, 7) )
>>> c.fill(7)
>>> a == c
False
Run Code Online (Sandbox Code Playgroud)
这似乎做对了.该类还应明确导出元素比较,因为这通常很有用.
Chr*_*ard 22
对我来说最大的问题是几乎每个标准运算符都过载以分布在整个阵列中.
定义列表和数组
>>> l = range(10)
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> import numpy
>>> a = numpy.array(l)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
Run Code Online (Sandbox Code Playgroud)
乘法复制python列表,但分布在numpy数组上
>>> l * 2
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a * 2
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
Run Code Online (Sandbox Code Playgroud)
在python列表中没有定义加法和除法
>>> l + 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list
>>> a + 2
array([ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
>>> l / 2.0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'list' and 'float'
>>> a / 2.0
array([ 0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5])
Run Code Online (Sandbox Code Playgroud)
Numpy重载有时会处理像数组这样的列表
>>> a + a
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
>>> a + l
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
Run Code Online (Sandbox Code Playgroud)
nik*_*kow 21
我觉得这个很有趣:
>>> import numpy as n
>>> a = n.array([[1,2],[3,4]])
>>> a[1], a[0] = a[0], a[1]
>>> a
array([[1, 2],
[1, 2]])
Run Code Online (Sandbox Code Playgroud)
另一方面,对于Python列表,这可以按预期工作:
>>> b = [[1,2],[3,4]]
>>> b[1], b[0] = b[0], b[1]
>>> b
[[3, 4], [1, 2]]
Run Code Online (Sandbox Code Playgroud)
有趣的旁注:numpy本身在shuffle函数中有一个错误,因为它使用了这种符号:-)(见这里).
原因是在第一种情况下我们正在处理数组的视图,因此值被就地覆盖.
Ant*_*sma 12
NaN不是单身之类的None,所以你不能真正使用它来检查它.是什么使得它有点棘手的是,NaN == NaN是False作为IEEE-754要求.这就是为什么你需要使用该numpy.isnan()函数来检查浮点数是否不是数字.或者math.isnan()如果您使用的是Python 2.6+ 标准库.
切片创建视图,而不是副本.
>>> l = [1, 2, 3, 4]
>>> s = l[2:3]
>>> s[0] = 5
>>> l
[1, 2, 3, 4]
>>> a = array([1, 2, 3, 4])
>>> s = a[2:3]
>>> s[0] = 5
>>> a
array([1, 2, 5, 4])
Run Code Online (Sandbox Code Playgroud)
小智 6
Numpy数组的真值与python序列类型的真值不同,其中任何非空序列都为真.
>>> import numpy as np
>>> l = [0,1,2,3]
>>> a = np.arange(4)
>>> if l: print "Im true"
...
Im true
>>> if a: print "Im true"
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: The truth value of an array with more than one element is ambiguous. Use
a.any() or a.all()
>>>
Run Code Online (Sandbox Code Playgroud)
数值类型在非零时为真,并且作为数字集合,numpy数组继承此定义.但是通过一组数字,真理可以合理地表示"所有元素都是非零"或"至少一个元素不为零".Numpy拒绝猜测哪个定义是什么意思,并引发上述异常.使用.any()和.all()方法可以指定true的含义.
>>> if a.any(): print "Im true"
...
Im true
>>> if a.all(): print "Im true"
...
>>>
Run Code Online (Sandbox Code Playgroud)
In [1]: bool([])
Out[1]: False
In [2]: bool(array([]))
Out[2]: False
In [3]: bool([0])
Out[3]: True
In [4]: bool(array([0]))
Out[4]: False
Run Code Online (Sandbox Code Playgroud)
因此,不要通过检查其真值来测试数组的空虚.使用size(array()).
并且不要使用len(array()):
In [1]: size(array([]))
Out[1]: 0
In [2]: len(array([]))
Out[2]: 0
In [3]: size(array([0]))
Out[3]: 1
In [4]: len(array([0]))
Out[4]: 1
In [5]: size(array(0))
Out[5]: 1
In [6]: len(array(0))
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-6-5b2872696128> in <module>()
----> 1 len(array(0))
TypeError: len() of unsized object
Run Code Online (Sandbox Code Playgroud)
(相关,但是NumPy与SciPy的关系,而不是NumPy与Python)
切片超出数组的实际大小的工作方式不同:
>>> import numpy, scipy.sparse
>>> m = numpy.random.rand(2, 5) # create a 2x5 dense matrix
>>> print m[:3, :] # works like list slicing in Python: clips to real size
[[ 0.12245393 0.20642799 0.98128601 0.06102106 0.74091038]
[ 0.0527411 0.9131837 0.6475907 0.27900378 0.22396443]]
>>> s = scipy.sparse.lil_matrix(m) # same for csr_matrix and other sparse formats
>>> print s[:3, :] # doesn't clip!
IndexError: row index out of bounds
Run Code Online (Sandbox Code Playgroud)
因此,在切片scipy.sparse数组时,必须手动确保切片边界在范围内.这与NumPy和普通Python的工作方式不同.