我有一个执行此操作的函数:它接受给定的numpy数组A
和给定的函数func
,并将该函数应用于数组的每个元素。
def transform(A, func):
return func(A)
A
和func
是从外部提供的,我无法控制它们。如果它们是transform(A, np.sin)
这样的矢量化函数,我希望这些函数能够工作,但我也希望能够接受正常的numpy函数,例如像transform(A, lambda x: x^2 if x > 5 else 0)
这样的lambdas。当然第二个没有矢量化,所以我需要在应用之前调用np.vectorize()
。像这样:transform(A, np.vectorize(lambda x: x^2 if x > 5 else 0))
...但我不想把这个负担强加给用户。我想对所有功能采用统一的方法。我只是从外面获得一个功能并应用它。
有没有一种方法可以决定哪种功能需要矢量化,哪种功能不需要?类似的东西:
def transform(A, func):
if requires_vectorization(func): # how to do this???
func = np.vectorize(func)
return func(A)
或者我应该在默认情况下全部矢量化
def transform(A, func):
func = np.vectorize(func) # is this correct and efficient?
return func(A)
这个解决方案好吗?换句话说,在已经向量化的函数上调用np.vectorize
是否有害?或者有其他选择吗?
答案 0 :(得分:2)
在EAFP principle之后,您可以先尝试直接在A
上调用该函数,看看是否会引发异常:
import numpy as np
def transform(A, func):
try:
return func(A)
except TypeError:
return np.vectorize(func)(A)
例如:
import math
A = np.linspace(0, np.pi, 5)
print(transform(A, np.sin)) # vectorized function
# [ 0.00000000e+00 7.07106781e-01 1.00000000e+00 7.07106781e-01
# 1.22464680e-16]
print(transform(A, math.sin)) # non-vectorized function
# [ 0.00000000e+00 7.07106781e-01 1.00000000e+00 7.07106781e-01
# 1.22464680e-16]
在已经向量化的函数上调用np.vectorize是否有害?
是的,绝对的。当你将np.vectorize
应用于一个函数时,所有循环输入数组元素都是在Python中完成的,这与在C中循环的“适当的”向量化numpy函数不同。来自the documentation:
提供矢量化功能主要是为了方便,而不是为了提高性能。 实施基本上是for循环。
我觉得这句话应该用粗体全文写成。
案例:
In [1]: vecsin = np.vectorize(np.sin)
In [2]: %%timeit A = np.random.randn(10000);
np.sin(A)
....:
1000 loops, best of 3: 243 µs per loop
In [3]: %%timeit A = np.random.randn(10000);
vecsin(A)
....:
100 loops, best of 3: 11.7 ms per loop
In [4]: %%timeit A = np.random.randn(10000);
[np.sin(a) for a in A]
....:
100 loops, best of 3: 12.5 ms per loop
在此示例中,将np.vectorize
应用于np.sin
可将其减慢约50倍,使其与常规Python列表理解速度一样慢。
为了完整性,这里是“转型”版本。如您所见,try
/ except
块对性能的影响可以忽略不计:
In [5]: %%timeit A = np.random.randn(10000);
transform(A, np.sin)
...:
1000 loops, best of 3: 241 µs per loop