在numpy数组上映射函数的最有效方法是什么?在我目前的项目中,我一直在这样做:
import numpy as np
x = np.array([1, 2, 3, 4, 5])
# Obtain array of square of each element in x
squarer = lambda t: t ** 2
squares = np.array([squarer(xi) for xi in x])
但是,这似乎非常低效,因为在将新数组转换回numpy数组之前,我使用列表理解将新数组构造为Python列表。
我们能做得更好吗?
发布于 2016-02-05 10:29:38
使用numpy.vectorize
怎么样?
import numpy as np
x = np.array([1, 2, 3, 4, 5])
squarer = lambda t: t ** 2
vfunc = np.vectorize(squarer)
vfunc(x)
# Output : array([ 1, 4, 9, 16, 25])
发布于 2016-02-05 12:36:05
TL;DR
正如@user2357112所指出的,应用函数的“直接”方法始终是在Numpy数组上映射函数的最快、最简单的方法:
import numpy as np
x = np.array([1, 2, 3, 4, 5])
f = lambda x: x ** 2
squares = f(x)
通常避免使用np.vectorize
,因为它的性能不是很好,并且有(或曾经)了许多issues。如果您正在处理其他数据类型,则可能需要研究如下所示的其他方法。
方法的比较
这里有一些简单的测试来比较三种映射函数的方法,本例使用Python3.6和NumPy 1.15.4。首先,用于测试的设置函数:
import timeit
import numpy as np
f = lambda x: x ** 2
vf = np.vectorize(f)
def test_array(x, n):
t = timeit.timeit(
'np.array([f(xi) for xi in x])',
'from __main__ import np, x, f', number=n)
print('array: {0:.3f}'.format(t))
def test_fromiter(x, n):
t = timeit.timeit(
'np.fromiter((f(xi) for xi in x), x.dtype, count=len(x))',
'from __main__ import np, x, f', number=n)
print('fromiter: {0:.3f}'.format(t))
def test_direct(x, n):
t = timeit.timeit(
'f(x)',
'from __main__ import x, f', number=n)
print('direct: {0:.3f}'.format(t))
def test_vectorized(x, n):
t = timeit.timeit(
'vf(x)',
'from __main__ import x, vf', number=n)
print('vectorized: {0:.3f}'.format(t))
使用五个元素进行测试(从快到慢排序):
x = np.array([1, 2, 3, 4, 5])
n = 100000
test_direct(x, n) # 0.265
test_fromiter(x, n) # 0.479
test_array(x, n) # 0.865
test_vectorized(x, n) # 2.906
有100个元素:
x = np.arange(100)
n = 10000
test_direct(x, n) # 0.030
test_array(x, n) # 0.501
test_vectorized(x, n) # 0.670
test_fromiter(x, n) # 0.883
并且具有上千个或更多的阵列元素:
x = np.arange(1000)
n = 1000
test_direct(x, n) # 0.007
test_fromiter(x, n) # 0.479
test_array(x, n) # 0.516
test_vectorized(x, n) # 0.945
不同版本的Python/NumPy和编译器优化会有不同的结果,所以针对您的环境进行类似的测试。
发布于 2016-02-05 10:36:17
squares = squarer(x)
数组上的算术操作是以元素为单位自动应用的,具有高效的C级循环,避免了适用于Python级循环或理解的所有解释器开销。
您希望应用于NumPy数组元素的大多数函数都将正常工作,尽管有些函数可能需要更改。例如,if
不能以元素的方式工作。您可能希望将它们转换为使用像numpy.where
这样的结构
def using_if(x):
if x < 5:
return x
else:
return x**2
变成了
def using_where(x):
return numpy.where(x < 5, x, x**2)
https://stackoverflow.com/questions/35215161
复制相似问题