繁体   English   中英

为什么numpy数组看起来不比标准的python列表快得多?

[英]Why does a numpy array not appear to be much faster than a standard python list?

根据我的理解,numpy数组可以比python列表更快地处理操作,因为它们是以并行而非迭代的方式处理的。 我试图测试它是为了好玩,但我没有看到太大的区别。

我的测试有问题吗? 区别仅仅比我使用的阵列大得多吗? 我确保在每个函数中创建一个python列表和numpy数组,以消除创建一个与另一个可能产生的差异,但时间增量实际上似乎可以忽略不计。 这是我的代码:

我的最终输出是numpy函数:6.534756324786595s,列表函数:6.559365831783256s

import timeit
import numpy as np

a_setup = 'import timeit; import numpy as np'

std_fx = '''
def operate_on_std_array():
    std_arr = list(range(0,1000000))
    np_arr = np.asarray(std_arr)
    for index,elem in enumerate(std_arr):
        std_arr[index] = (elem**20)*63134
    return std_arr
'''
parallel_fx = '''
def operate_on_np_arr():
    std_arr = list(range(0,1000000))
    np_arr = np.asarray(std_arr)
    np_arr = (np_arr**20)*63134
    return np_arr
'''

def operate_on_std_array():
    std_arr = list(range(0,1000000))
    np_arr = np.asarray(std_arr)
    for index,elem in enumerate(std_arr):
        std_arr[index] = (elem**20)*63134
    return std_arr

def operate_on_np_arr():
    std_arr = list(range(0,1000000))
    np_arr = np.asarray(std_arr)
    np_arr = (np_arr**20)*63134
    return np_arr


print('std',timeit.timeit(setup = a_setup, stmt = std_fx, number = 80000000))
print('par',timeit.timeit(setup = a_setup, stmt = parallel_fx, number = 80000000))



#operate_on_np_arr()
#operate_on_std_array()

这里的timeit文档显示你传入的语句应该执行某些东西,但是你传入的语句只是定义函数。 我想在一个100万个长度的阵列上进行80000000次试验需要花费更长的时间。

您在测试中遇到的其他问题:

  • np_arr = (np_arr**20)*63134可能会创建np_arr的副本,但您的Python等效列表只会改变现有数组。
  • Numpy数学与Python数学不同。 Python中的100**20返回一个巨大的数字,因为Python具有无界长度的整数,但是Numpy使用溢出的C风格的固定长度整数。 (一般情况下,当你使用Numpy时,你必须想象在C中进行操作,因为其他不直观的东西可能适用,比如未初始化数组中的垃圾。)

这是一个测试,我在那里修改两者,然后乘以每次除以31,这样值不会随着时间或溢出而改变:

import numpy as np
import timeit

std_arr = list(range(0,100000))
np_arr = np.array(std_arr)
np_arr_vec = np.vectorize(lambda n: (n * 31) / 31)

def operate_on_std_array():
    for index,elem in enumerate(std_arr):
        std_arr[index] = elem * 31
        std_arr[index] = elem / 31
    return std_arr

def operate_on_np_arr():
    np_arr_vec(np_arr)
    return np_arr


import time
def test_time(f):
    count = 100
    start = time.time()
    for i in range(count):
        f()
    dur = time.time() - start
    return dur

print(test_time(operate_on_std_array))
print(test_time(operate_on_np_arr))

结果:

3.0798873901367188 # standard array time
2.221336841583252 # np array time

编辑:正如@ user2357112指出的那样,正确的Numpy方法是这样的:

def operate_on_np_arr():
    global np_arr
    np_arr *= 31
    np_arr //= 31 # integer division, not double
    return np_arr

使它更快。 我看到0.1248秒。

以下是使用ipython magic初始化列表和/或数组的一些计时。 结果应该集中在计算上:

In [103]: %%timeit alist = list(range(10000))
     ...: for i,e in enumerate(alist):
     ...:    alist[i] = (e*3)*20
     ...: 
4.13 ms ± 146 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [104]: %%timeit arr = np.arange(10000)
     ...: z = (arr*3)*20
     ...: 
20.6 µs ± 439 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [105]: %%timeit alist = list(range(10000))
     ...: z = [(e*3)*20 for e in alist]
     ...: 
     ...: 
1.71 ms ± 2.69 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

看一下数组创建时间的影响:

In [106]: %%timeit alist = list(range(10000))
     ...: arr = np.array(alist)
     ...: z = (arr*3)*20
     ...: 
     ...: 
1.01 ms ± 43.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

好的,计算方法不一样。 如果我使用**3代替,所有时间都大约2倍。 相同的相对关系。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM