代码之家  ›  专栏  ›  技术社区  ›  denis

知道numpy和纯蟒蛇有什么不同吗?

  •  25
  • denis  · 技术社区  · 17 年前

    乡亲们,

    有没有一个gotchas的集合,numpy和python不同, 困惑和花费时间的要点?

    “那一刻的恐怖,我会 永远不要忘记!”
    “不过,如果你不这样做,你会的,”女王说。 做一份备忘录。”

    例如,奶奶在任何地方都是麻烦。 如果你不用运行就可以解释这一点,给自己一个点--

    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] )
    

    (我不是在敲麻木,那里有很多好的工作,只是认为一个常见问题解答或gotchas的wiki会有用。)

    编辑:我希望能收集六个gotchas(让学习麻木的人感到惊讶)。
    那么,如果有共同的理解,或者更好的,共同的解释, 我们可以讨论将它们添加到社区wiki(在哪里?) 到目前为止,我们似乎还不够。

    15 回复  |  直到 7 年前
        1
  •  22
  •   Christian Oudard    17 年前

    对我来说,最大的问题是几乎所有的标准操作符都超载了,无法在数组中分布。

    定义列表和数组

    >>> 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])
    

    乘法复制了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])
    

    在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])
    

    有时使用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])
    
        2
  •  24
  •   Nathan Wilcox    15 年前

    因为 __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()
    

    这是一个可怕的问题。例如,不能为使用 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) )
    

    现在,我们必须为可能用于存储numpy数组的每种容器类型执行此操作。此外, 爱斯克 可能返回bool而不是bool数组:

    >>> a = numpy.array(range(3))
    >>> b = numpy.array(range(5))
    >>> a == b
    False
    

    现在,每个容器特定的相等比较函数也必须处理这种特殊情况。

    也许我们可以用一个子类来修补这个疣?

    >>> 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
    

    这似乎做得对。类还应该显式导出元素比较,因为这通常很有用。

        3
  •  21
  •   nikow    15 年前

    我觉得这个很有趣:

    >>> 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]])
    

    另一方面,对于python列表,这是按预期工作的:

    >>> b = [[1,2],[3,4]]
    >>> b[1], b[0] = b[0], b[1]
    >>> b
    [[3, 4], [1, 2]]
    

    有趣的旁注:麻木本身在 shuffle 函数,因为它使用了这个符号:-)(请参见 here )

    原因是,在第一个案例中,我们正在处理 意见 数组的值,因此值将被就地覆盖。

        4
  •  12
  •   Ants Aasma    17 年前

    NaN 不是单身汉吗 None ,所以您不能真正使用IS检查。有点棘手的是 NaN == NaN 是 False 根据IEEE-754的要求。这就是为什么你需要使用 numpy.isnan() 函数检查浮点数是否不是数字。或者标准库 math.isnan() 如果您使用的是python 2.6+。

        5
  •  7
  •   Roberto Bonvallet    17 年前

    切片创建视图,而不是副本。

    >>> 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])
    
        6
  •  6
  •   endolith    10 年前
    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
    

    所以不要通过检查数组的真值来测试它的空性。使用 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
    
        7
  •  6
  •   ascripter    7 年前

    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()
    >>>
    

    当数字类型为非零时,它们为真;作为数字集合,numpy数组继承此定义。但有了一组数字,真理可以合理地表示“所有元素都是非零的”或者“至少有一个元素是非零的”。numpy拒绝猜测哪个定义的含义,并引发了上述异常。使用 .any() 和 .all() 方法允许指定“真”的含义。

    >>> if a.any(): print "Im true"
    ... 
    Im true
    >>> if a.all(): print "Im true"
    ... 
    >>>
    
        8
  •  5
  •   Radim    15 年前

    (相关的,但麻木与坐骨神经痛的对比,而不是麻木与巨蟒的对比)


    数组实际大小之外的切片工作方式不同:

    >>> 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
    

    所以切片时 scipy.sparse 数组,必须手动确保切片边界在范围内。这与numpy和plain python的工作方式不同。

        9
  •  3
  •   Lennart Regebro    17 年前
    print pynan is pynan, pynan is NaN, NaN is NaN
    

    这测试身份,也就是说如果它是同一个对象。因此,结果显然应该是真、假、真,因为当您执行float(无论什么)操作时,您正在创建一个新的float对象。

    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] )
    

    这是我必须跑的。:-)当您将NaN插入数组时,它将转换为numpy.float64对象,这就是为什么[1]是NaN失败的原因。

    对我来说,这一切似乎都相当不足为奇。但我对麻木的了解不多。-)

        10
  •  3
  •   DSM    13 年前

    到目前为止似乎还没有人提到:

    >>> all(False for i in range(3))
    False
    >>> from numpy import all
    >>> all(False for i in range(3))
    True
    >>> any(False for i in range(3))
    False
    >>> from numpy import any
    >>> any(False for i in range(3))
    True
    

    努米 any 和 all 不要和发电机玩得很好,也不要向你发出错误警告,他们不会。

        11
  •  2
  •   denis    17 年前

    来自Neil Martinsen Burrell in numpy-discussion 7个月——

    numpy中可用的ndarray类型是 在概念上不是 巨蟒的Iterables。如果你愿意的话 帮助其他麻木的用户 问题,您可以编辑文档 在联机文档编辑器中 numpy-docs

        12
  •  2
  •   sillyMunky    16 年前

    我发现事实上,将元素列表相乘只会创建元素视图,这让我陷入困境。

    >>> a=[0]*5
    >>>a
    [0,0,0,0,0]
    >>>a[2] = 1
    >>>a
    [0,0,1,0,0]
    >>>b = [np.ones(3)]*5
    >>>b
    [array([ 1.,  1.,  1.]), array([ 1.,  1.,  1.]), array([ 1.,  1.,  1.]), array([ 1.,  1.,  1.]), array([ 1.,  1.,  1.])]
    >>>b[2][1] = 2
    >>>b
    [array([ 1.,  2.,  1.]), array([ 1.,  2.,  1.]), array([ 1.,  2.,  1.]), array([ 1.,  2.,  1.]), array([ 1.,  2.,  1.])]
    

    所以,如果您创建一个这样的元素列表,并打算对它们执行不同的操作,那么您将被破坏……

    一个简单的解决方案是迭代创建每个数组(使用“for loop”或列表理解)或使用更高维度的数组(例如,这些一维数组中的每一个都是二维数组中的一行,通常速度更快)。

        13
  •  2
  •   jolvi    11 年前

    不是什么大问题:有了布尔切片,我有时候真希望自己能做到。

      x[ 3 <= y < 7 ]
    

    类似于python的双重比较。相反,我必须写

      x[ np.logical_and(3<=y, y<7) ]
    

    (除非你知道更好的事情?)

    另外,np.logical_和np.logical_或每个只接受两个参数,我希望它们接受一个变量号或列表,这样我就可以输入两个以上的逻辑子句。

    (numpy 1.3,可能这在以后的版本中都发生了变化。)

        14
  •  2
  •   jolvi    11 年前

    一个惊喜 *= 作业与 numpy.array :

    >>> from numpy import array
    
    >>> a = array([1, 2, 3])
    >>> a *= 1.1  
    >>> print(a) 
    [1 2 3]  # not quite what we expect or would like to see
    
    >>> print(a.dtype)
    int64  # and this is why
    
    >>> a = 1.1 * a  # here, a new array is created
    >>> print(a, a.dtype)
    [ 1.1  2.2  3.3] float64  # with the expected outcome
    

    令人惊讶,恼人,但可以理解。这个 *= 操作员不会更改 array 数据,从而使 int 数组 由A float 在这个乘法的传统意义上是失败的。python版本 a = 1; a *= 1.1 另一方面,按预期工作。

        15
  •  1
  •   alfa    13 年前

    无的0-D数组看起来像无,但它不同:

    In [1]: print None
    None
    
    In [2]: import numpy
    
    In [3]: print numpy.array(None)
    None
    
    In [4]: numpy.array(None) is None
    Out[4]: False
    
    In [5]: numpy.array(None) == None
    Out[5]: False
    
    In [6]: print repr(numpy.array(None))
    array(None, dtype=object)