Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python';s sum vs.NumPy';s numpy.sum_Python_Performance_Numpy_Python 3.x - Fatal编程技术网

Python';s sum vs.NumPy';s numpy.sum

Python';s sum vs.NumPy';s numpy.sum,python,performance,numpy,python-3.x,Python,Performance,Numpy,Python 3.x,使用Python的原生sum函数和NumPy的NumPy.sum函数在性能和行为上有什么不同sum适用于NumPy的数组,NumPy.sum适用于Python列表,它们都返回相同的有效结果(没有测试溢出等边缘情况),但类型不同 >>> import numpy as np >>> np_a = np.array(range(5)) >>> np_a array([0, 1, 2, 3, 4]) >>> type(np_a)

使用Python的原生
sum
函数和NumPy的
NumPy.sum
函数在性能和行为上有什么不同
sum
适用于NumPy的数组,
NumPy.sum
适用于Python列表,它们都返回相同的有效结果(没有测试溢出等边缘情况),但类型不同

>>> import numpy as np
>>> np_a = np.array(range(5))
>>> np_a
array([0, 1, 2, 3, 4])
>>> type(np_a)
<class 'numpy.ndarray')

>>> py_a = list(range(5))
>>> py_a
[0, 1, 2, 3, 4]
>>> type(py_a)
<class 'list'>

# The numerical answer (10) is the same for the following sums:
>>> type(np.sum(np_a))
<class 'numpy.int32'>
>>> type(sum(np_a))
<class 'numpy.int32'>
>>> type(np.sum(py_a))
<class 'numpy.int32'>
>>> type(sum(py_a))
<class 'int'>
>>将numpy作为np导入
>>>np_a=np.数组(范围(5))
>>>np_a
数组([0,1,2,3,4])
>>>类型(np_a)
>>py_a=列表(范围(5))
>>>皮尤
[0, 1, 2, 3, 4]
>>>类型(py_a)
#对于以下总和,数值答案(10)相同:
>>>类型(np.和(np_a))
>>>类型(总和(np_a))
>>>类型(np.总和(py_a))
>>>类型(总和(py_a))
Edit:我想我的实际问题是在Python整数列表上使用
numpy.sum
会比使用Python自己的
sum
快吗

此外,使用Python整数与使用标量
numpy.int32
相比,有什么意义(包括性能)?例如,对于
a+=1
,如果
a
的类型是Python整数或
numpy.int32
,是否存在行为或性能差异?我很好奇,对于Python代码中大量增加或减少的值,使用NumPy标量数据类型(如
NumPy.int32
)是否更快

为了澄清,我正在进行一项生物信息学模拟,其中部分内容包括将多维
numpy.ndarray
s压缩为单个标量和,然后进行额外处理。我正在使用Python 3.2和NumPy 1.6


提前谢谢

Numpy应该快得多,尤其是当您的数据已经是一个Numpy数组时

Numpy阵列是标准C阵列上的薄层。当numpysum迭代这个过程时,它不会进行类型检查,而且速度非常快。速度应与使用标准C进行操作相当

相比之下,使用python的sum必须首先将numpy数组转换为python数组,然后迭代该数组。它必须做一些类型检查,而且通常会比较慢


python sum比numpy sum慢的确切数量没有得到很好的定义,因为与用python编写自己的sum函数相比,python sum将是一个稍微优化的函数。

我很好奇,并对它进行了计时<对于numpy数组,code>numpy.sum似乎要快得多,但在列表中要慢得多

import numpy as np
import timeit

x = range(1000)
# or 
#x = np.random.standard_normal(1000)

def pure_sum():
    return sum(x)

def numpy_sum():
    return np.sum(x)

n = 10000

t1 = timeit.timeit(pure_sum, number = n)
print 'Pure Python Sum:', t1
t2 = timeit.timeit(numpy_sum, number = n)
print 'Numpy Sum:', t2
x=范围(1000)
时的结果:

x=np.random.standard\u normal(1000)
时的结果:


我使用的是Python 2.7.2和Numpy 1.6.1请注意,多维Numpy数组上的Python sum将仅沿第一个轴执行求和:

sum(np.array([[[2,3,4],[4,5,6]],[[7,8,9],[10,11,12]]]))
Out[47]: 
array([[ 9, 11, 13],
       [14, 16, 18]])

np.sum(np.array([[[2,3,4],[4,5,6]],[[7,8,9],[10,11,12]]]), axis=0)
Out[48]: 
array([[ 9, 11, 13],
       [14, 16, 18]])

np.sum(np.array([[[2,3,4],[4,5,6]],[[7,8,9],[10,11,12]]]))
Out[49]: 81

这是对的扩展。从这个答案可以看出
np.sum
对于
np.array
对象执行得更快,而
sum
对于
list
对象执行得更快。进一步说:

np.array
对象运行
np.sum
时,与对
列表
对象运行
sum
时,它们的性能似乎不相上下

# I'm running IPython

In [1]: x = range(1000) # list object

In [2]: y = np.array(x) # np.array object

In [3]: %timeit sum(x)
100000 loops, best of 3: 14.1 µs per loop

In [4]: %timeit np.sum(y)
100000 loops, best of 3: 14.3 µs per loop
如上所述,
sum
np.array
快一点点,尽管有时我也看到
np.sum
计时为
14.1µs
。但主要是
14.3µs

[…]我的[…]问题是在Python整数列表上使用
numpy.sum
会比使用Python自己的
sum
快吗

这个问题的答案是:不

Pythons求和在列表上会更快,而NumPys求和在数组上会更快。我实际上做了一个基准测试来显示计时(Python 3.6,NumPy 1.14):

左:在NumPy数组上;右:在Python列表中。 请注意,这是一个日志图,因为基准涵盖了非常广泛的值。然而,对于定性结果:越低意味着越好

这表明对于列表,python
sum
总是更快,而
np.sum
或数组上的
sum
方法将更快(除了python
sum
更快的非常短的数组)

以防万一,你有兴趣将它们相互比较,我还画了一个图,包括所有这些:

f, ax = plt.subplots(1)
b_array.plot(ax=ax)
b_list.plot(ax=ax)
ax.grid(which='both')

有趣的是,
numpy
在数组上与Python和list的竞争点大约在200个元素左右!请注意,这个数字可能取决于很多因素,例如Python/NumPy版本。。。不要太直截了当

没有提到的是这种差异的原因(我指的是大规模差异,而不是短列表/数组的差异,在短列表/数组中,函数只是具有不同的常量开销)。假设Python列表中的CPython是指向Python对象(在本例中为Python整数)的指针的C(语言C)数组的包装器。这些整数可以看作是C整数的包装(实际上并不正确,因为Python整数可以任意大,所以它不能简单地使用oneC整数,但它已经足够接近了)

例如,像
[1,2,3]
这样的列表(示意图上,我省略了一些细节)存储如下:

然而,NumPy数组是包含C值的C数组的包装器(在本例中,
int
long
取决于32位或64位,取决于操作系统)

所以像
np.array([1,2,3])
这样的NumPy数组如下所示:

接下来要了解的是这些函数是如何工作的:

  • Pythons
    sum
    迭代iterable(在本例中为列表或数组)并添加所有元素
  • NumPys
    sum
    方法迭代存储的C数组并添加这些C值,最后将该值包装为Python类型(在本例中为
    numpy.int32
    (或
    numpy.int64
    )并返回它
  • 纽皮斯<
    # I'm running IPython
    
    In [1]: x = range(1000) # list object
    
    In [2]: y = np.array(x) # np.array object
    
    In [3]: %timeit sum(x)
    100000 loops, best of 3: 14.1 µs per loop
    
    In [4]: %timeit np.sum(y)
    100000 loops, best of 3: 14.3 µs per loop
    
    import random
    import numpy as np
    import matplotlib.pyplot as plt
    
    from simple_benchmark import benchmark
    
    %matplotlib notebook
    
    def numpy_sum(it):
        return np.sum(it)
    
    def python_sum(it):
        return sum(it)
    
    def numpy_sum_method(arr):
        return arr.sum()
    
    b_array = benchmark(
        [numpy_sum, numpy_sum_method, python_sum],
        arguments={2**i: np.random.randint(0, 10, 2**i) for i in range(2, 21)},
        argument_name='array size',
        function_aliases={numpy_sum: 'numpy.sum(<array>)', numpy_sum_method: '<array>.sum()', python_sum: "sum(<array>)"}
    )
    
    b_list = benchmark(
        [numpy_sum, python_sum],
        arguments={2**i: [random.randint(0, 10) for _ in range(2**i)] for i in range(2, 21)},
        argument_name='list size',
        function_aliases={numpy_sum: 'numpy.sum(<list>)', python_sum: "sum(<list>)"}
    )
    
    f, (ax1, ax2) = plt.subplots(1, 2, sharey=True)
    b_array.plot(ax=ax1)
    b_list.plot(ax=ax2)
    
    f, ax = plt.subplots(1)
    b_array.plot(ax=ax)
    b_list.plot(ax=ax)
    ax.grid(which='both')
    
    from itertools import repeat
    
    python_integer = 1000
    numpy_integer_32 = np.int32(1000)
    numpy_integer_64 = np.int64(1000)
    
    def repeatedly_add_one(val):
        for _ in repeat(None, 100000):
            _ = val + 1
    
    %timeit repeatedly_add_one(python_integer)
    3.7 ms ± 71.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    %timeit repeatedly_add_one(numpy_integer_32)
    14.3 ms ± 162 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    %timeit repeatedly_add_one(numpy_integer_64)
    18.5 ms ± 494 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    
    def repeatedly_sub_one(val):
        for _ in repeat(None, 100000):
            _ = val - 1
    
    %timeit repeatedly_sub_one(python_integer)
    3.75 ms ± 236 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    %timeit repeatedly_sub_one(numpy_integer_32)
    15.7 ms ± 437 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    %timeit repeatedly_sub_one(numpy_integer_64)
    19 ms ± 834 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    def repeatedly_add_one(val):
        one = type(val)(1)  # create a 1 with the same type as the input
        for _ in repeat(None, 100000):
            _ = val + one
    
    %timeit repeatedly_add_one(python_integer)
    3.88 ms ± 273 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    %timeit repeatedly_add_one(numpy_integer_32)
    6.12 ms ± 324 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    %timeit repeatedly_add_one(numpy_integer_64)
    6.49 ms ± 265 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    a = np.arange(6).reshape(2, 3)
    print(a)
    print(sum(a))
    print(sum(sum(a)))
    print(np.sum(a))
    
    
    >>>
    [[0 1 2]
     [3 4 5]]
    [3 5 7]
    15
    15