为什么numpy比python慢?如何提高代码性能

9

我将神经网络从纯Python改写为NumPy,但现在它运行得更慢了。因此,我尝试使用以下两个函数:

def d():
    a = [1,2,3,4,5]
    b = [10,20,30,40,50]
    c = [i*j for i,j in zip(a,b)]
    return c

def e():
    a = np.array([1,2,3,4,5])
    b = np.array([10,20,30,40,50])
    c = a*b
    return c

timeit d = 1.77135205057

timeit e = 17.2464673758

Numpy慢了10倍。为什么会这样,如何正确使用numpy?


可能相关:https://dev59.com/XW025IYBdhLWcg3whGax - Tamás
1
你应该使用更大的数组来进行这种测试。 - Ruggero Turra
5个回答

14

我会假设这个差异是因为你在e中构建了列表和数组,而你只在d中构建了列表。请参考:

import numpy as np

def d():
    a = [1,2,3,4,5]
    b = [10,20,30,40,50]
    c = [i*j for i,j in zip(a,b)]
    return c

def e():
    a = np.array([1,2,3,4,5])
    b = np.array([10,20,30,40,50])
    c = a*b
    return c

#Warning:  Functions with mutable default arguments are below.
# This code is only for testing and would be bad practice in production!
def f(a=[1,2,3,4,5],b=[10,20,30,40,50]):
    c = [i*j for i,j in zip(a,b)]
    return c

def g(a=np.array([1,2,3,4,5]),b=np.array([10,20,30,40,50])):
    c = a*b
    return c


import timeit
print timeit.timeit('d()','from __main__ import d')
print timeit.timeit('e()','from __main__ import e')
print timeit.timeit('f()','from __main__ import f')
print timeit.timeit('g()','from __main__ import g')

这里的函数fg避免了每次循环重新创建列表/数组,因此我们获得了非常相似的性能:

1.53083586693
15.8963699341
1.33564996719
1.69556999207

请注意,列表推导和zip仍然是最快的。但是,如果我们使用足够大的数组,NumPy则毫无疑问地胜出:

Note that list-comp + zip still wins. However, if we make the arrays sufficiently big, numpy wins hands down:
t1 = [1,2,3,4,5] * 100
t2 = [10,20,30,40,50] * 100
t3 = np.array(t1)
t4 = np.array(t2)
print timeit.timeit('f(t1,t2)','from __main__ import f,t1,t2',number=10000)
print timeit.timeit('g(t3,t4)','from __main__ import g,t3,t4',number=10000)

我的结果是:

0.602419137955
0.0263929367065

3
import time , numpy
def d():
    a = range(100000)
    b =range(0,1000000,10)
    c = [i*j for i,j in zip(a,b)]
    return c

def e():
    a = numpy.array(range(100000))
    b =numpy.array(range(0,1000000,10))
    c = a*b
    return c



#python ['0.04s', '0.04s', '0.04s']
#numpy ['0.02s', '0.02s', '0.02s']

尝试使用更大的数组...即使创建数组的开销很大,numpy仍然更快。


1
2倍相对于小数据的10倍损失来说微不足道。很容易成为开销成本的受害者。 - John Jiang
非常有价值的观点。 - Joran Beasley

2

Numpy数据结构在添加/构建时速度较慢

以下是一些测试:

from timeit import Timer
setup1 = '''import numpy as np
a = np.array([])'''
stmnt1 = 'np.append(a, 1)'
t1 = Timer(stmnt1, setup1)

setup2 = 'l = list()'
stmnt2 = 'l.append(1)'
t2 = Timer(stmnt2, setup2)

print('appending to empty list:')
print(t1.repeat(number=1000))
print(t2.repeat(number=1000))

setup1 = '''import numpy as np
a = np.array(range(999999))'''
stmnt1 = 'np.append(a, 1)'
t1 = Timer(stmnt1, setup1)

setup2 = 'l = [x for x in xrange(999999)]'
stmnt2 = 'l.append(1)'
t2 = Timer(stmnt2, setup2)

print('appending to large list:')
print(t1.repeat(number=1000))
print(t2.repeat(number=1000))

结果:

appending to empty list:
[0.008171333983972538, 0.0076482562944814175, 0.007862921943675175]
[0.00015624398517267296, 0.0001191077336243837, 0.000118654852507942]
appending to large list:
[2.8521017080411304, 2.8518707386717446, 2.8022625940577477]
[0.0001643958452675065, 0.00017888804099541744, 0.00016711313196715594]

0
import time , numpy
def d():
    a = range(100000)
    b =range(0,1000000,10)
    c = [i*j for i,j in zip(a,b)]
    return c

def e():
    a = numpy.array(np.arange(100000))
    b = numpy.array(np.arange(0,1000000,10))
    c = a*b
    return c

pure python
t1 = time.time()
d()
t2 = time.time()

print(t2-t1) 
time difference : 0.02503204345703125
with numpy
t1 = time.time()
e()
t2 = time.time()

print(t2-t1) 
time difference : 0.0010941028594970703
thus numpy is much faster

你的回答可以通过添加支持信息来改进。请编辑并添加更多细节。 - user7247147

-1

我认为numpy并不慢,因为它必须考虑编写和调试所需的时间。程序越长,找到问题或添加新功能就越困难(程序员的时间)。因此,在相同的智力时间和技能下使用更高级别的语言可以创建一个复杂且潜在更有效的程序。

无论如何,一些有趣的优化工具包括:

-Psyco是一个JIT(即时,“实时”)编译器,可以在运行时优化代码。

-Numexpr,并行化是加速程序执行的好方法,前提是足够可分离。

-Weave是NumPy中的一个模块,用于通信Python和C。其中一个函数是blitz,它接受一行Python代码,透明地将其转换为C,并在每次调用时执行优化版本。进行这种第一次转换需要大约一秒钟,但通常可以获得更高的速度。它不像Numexpr或Psyco字节码,也不像NumPy那样与C接口,而是直接用C编写的自己的函数,并完全编译和优化。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接