【问题标题】:Using numpy ufuncs vs built-in operators使用 numpy ufunc 与内置运算符
【发布时间】:2013-03-28 18:13:46
【问题描述】:

我很好奇使用 numpy ufuncs 与内置运算符与内置运算符的“函数”版本的好处和权衡。

我对所有 ufunc 都很好奇。也许有时候有些比其他的更有用。不过,为了简单起见,我将在示例中使用<

有几种方法可以通过单个数字“过滤”一个 numpy 数组以获得一个布尔数组。每种形式都给出相同的结果,但是否有首选的时间/地点来使用其中的一种?这个例子我将一个数组与一个数字进行比较,所以所有 3 都可以工作。

考虑使用以下数组的所有示例:

>>> x = numpy.arange(0, 10000)
>>> x
array([   0,    1,    2, ..., 9997, 9998, 9999])

'
>>> x < 5000
array([ True,  True,  True, ..., False, False, False], dtype=bool)
>>> %timeit x < 5000
100000 loops, best of 3: 15.3 us per loop

operator.lt

>>> import operator
>>> operator.lt(x, 5000)
array([ True,  True,  True, ..., False, False, False], dtype=bool)
>>> %timeit operator.lt(x, 5000)
100000 loops, best of 3: 15.3 us per loop

numpy.less

>>> numpy.less(x, 5000)
array([ True,  True,  True, ..., False, False, False], dtype=bool)
>>> %timeit numpy.less(x, 5000)
100000 loops, best of 3: 15 us per loop

请注意,它们都实现了几乎相同的性能和完全相同的结果。我猜所有这些调用实际上最终都在同一个函数中,因为&lt;operator.lt 都映射到一个numpy 数组上的__lt__,这可能是使用numpy.less 或等效的实现的?

那么,哪个更“惯用”和“首选”?

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    一般来说,考虑到“可读性很重要”的口头禅,实际的运算符应该始终是您的首选。使用operator 版本有一个地方,您可以将lambda a, b: a &lt; b 替换为更紧凑的operator.lt,但除此之外没有太多。而且你真的不应该使用对相应 ufunc 的显式调用,除非你想使用 out 参数将计算值直接存储在现有数组中。

    也就是说,如果你担心的是性能,你应该做公平的比较,因为正如你所说,你所有的调用最终都由numpy的lessufunc处理。

    如果您的数据已经在一个 numpy 数组中,那么您已经证明它们的性能都相似,所以为了清楚起见,请使用 &lt; 运算符。

    如果您的数据在 python 对象中,比如说一个列表,该怎么办?好吧,这里有一些时间供你思考:

    In [13]: x = range(10**5)
    
    In [19]: %timeit [j < 5000 for j in x]
    100 loops, best of 3: 5.32 ms per loop
    
    In [20]: %timeit np.less(x, 5000)
    100 loops, best of 3: 11.3 ms per loop
    
    In [21]: %timeit [operator.lt(j, 5000) for j in x]
    100 loops, best of 3: 16.2 ms per loop
    

    不知道为什么operator.lt 这么慢,但你显然想远离它。如果您想从 Python 对象输入中获取一个 numpy 数组作为输出,那么这可能是最快的:

    In [22]: %timeit np.fromiter((j < 5000 for j in x), dtype=bool, count=10**5)
    100 loops, best of 3: 7.91 ms per loop
    

    请注意,在 numpy 数组上运行的 ufunc 比上述任何方法都快

    In [24]: y = np.array(x)
    
    In [25]: %timeit y < 5000
    10000 loops, best of 3: 82.8 us per loop
    

    【讨论】:

    • 谢谢!在您的所有示例中,x 是标准 Python 列表?
    【解决方案2】:

    在这种情况下,首选形式是 x &lt; 5000,因为它更简单,而且您已经在使用 numpy 数组。

    ufuncs 旨在允许对任何类型的数据(不仅仅是 numpy 数组)进行这些操作

    >>> numpy.less([1, 2, 3, 4, 6, 8], 5)
    array([ True,  True,  True,  True, False, False], dtype=bool)
    
    >>> [1, 2, 3, 4, 6, 8] < 5
    False
    

    在 Python 3 上,最后的比较会引发错误。

    【讨论】:

    • 这是有道理的,但是 numpy 文档似乎不同意您的说法,即它们不仅仅适用于 numpy 数组:“通用函数(或简称 ufunc)是在 ndarrays 上运行的函数一种逐元素的方式,支持数组广播、类型转换和其他几个标准特性。”我从您的示例中看到它确实与列表一起使用,但是除非我阅读文档的含义过于密切,否则某些事情会发生冲突。
    • 另外,我同意&lt; 在这种情况下更合适。只是感觉更自然。所以,这就引出了一个有点相关的问题,我什么时候应该使用ufuncs?
    • 它适用于 ndarray,但适用于列表和元组,因为它们是 Python 的基本容器,并且您的大多数数据可能已经在使用这些类型。使用 ufuncs 或多或少类似于首先在您的元素上调用 asarray
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多