Python中高效的元素函数计算
我有以下优化问题。给定两个np.arrayPython中高效的元素函数计算,python,numpy,scikit-learn,vectorization,Python,Numpy,Scikit Learn,Vectorization,我有以下优化问题。给定两个np.arrayX,Y和一个函数K,我希望尽可能快地计算矩阵关联gram\u矩阵,其中(I,j)-th元素计算为K(X[I],Y[j]) 这里有一个使用嵌套for循环的实现,它被认为是解决此类问题最慢的 def proxy_kernel(X,Y,K): gram_matrix = np.zeros((X.shape[0], Y.shape[0])) for i, x in enumerate(X): for j, y in enumera
X
,Y
和一个函数K
,我希望尽可能快地计算矩阵关联gram\u矩阵,其中(I,j)-th
元素计算为K(X[I],Y[j])
这里有一个使用嵌套for循环的实现,它被认为是解决此类问题最慢的
def proxy_kernel(X,Y,K):
gram_matrix = np.zeros((X.shape[0], Y.shape[0]))
for i, x in enumerate(X):
for j, y in enumerate(Y):
gram_matrix[i, j] = K(x, y)
return gram_matrix
非常感谢您的帮助 您至少可以将内部循环矢量化:
def proxy_kernel_vect(X, Y, K):
K_vect = np.vectorize(K)
gram_matrix = np.zeros((X.shape[0], Y.shape[0]))
for i, x in enumerate(X):
gram_matrix[i] = K_vect(x, Y)
return gram_matrix
这对相对较长的阵列产生了很好的改进:
In [15]: a = np.array(range(1000))
...: b = np.array(range(1000))
...:
In [16]: %timeit proxy_kernel(a, b, k)
1 loops, best of 3: 665 ms per loop
In [17]: %timeit proxy_kernel_vect(a, b, k)
1 loops, best of 3: 266 ms per loop
其中
k
只是lambda x,y:x+y
np.vectorize
确实在速度上有所提高,大约是2x(这里我使用math.atan2
作为一个黑盒函数,它接受两个标量参数)
在哪里
只要K
是一个黑匣子,您就会受到调用K
X.shape[0]*Y.shape[0]次数的限制。您可以尝试最小化迭代时间,但仍然受到所有这些函数调用的限制
利用
np.linalg.norm
函数的轴
参数,使用高斯核加速计算。您也可以尝试从模块中对装饰器进行矢量化
您可以使用矢量化和numpy轻松解决特定问题:
在代码复查时询问此问题可能会更好。如果不知道K
是什么,您将不会比嵌套循环做得更好。不幸的是,K是作为参数传递的。令人难过的是,这个实现非常慢,但到目前为止,它是唯一有效的;它将在这里得到比代码审查更多的答案。只要K
是一个只接受标量的黑匣子,就没有多少方法可以提高速度。但首先,将典型的K
的时间与最简单的K
的时间进行比较。迭代花费了多少时间,评估K
无数次又花了多少时间?这里你的K
是什么?我不认为以这种方式应用vectorize
实际上保留了原始语义。@user2357112它在答案的最后一行中定义。它只是一个标量函数(因为OP似乎就是这么用的),我不认为它应该是一个标量函数。在“Gram矩阵”的通常定义中,函数是内积。@Bakuriu谢谢。不幸的是,这在我的代码gram_矩阵[i]=vect(x,Y)ValueError:无法将输入数组从形状(600,2)广播到形状(600)
给定名称gram_矩阵
,我很确定K
应该是两个向量的函数,不是两个标量。在CR上,他引用了机器学习核函数;但他仍然不清楚尺寸;为什么使用矢量化会带来加速?我认为矢量化只是让代码更漂亮,但在内部仍然只是一个for循环?在这种情况下我不知道<代码>矢量化
使用来自PyFunc的frompyfunc
的测试速度通常是显式循环的2倍,但是vectorize
的开销更大,而且通常速度稍慢。但我不太在意2倍的差异。我们想要的是np.arctan2
提供的10倍差异。
In [486]: X=np.linspace(0,1,100)
In [487]: K_vect=np.vectorize(math.atan2)
In [488]: timeit proxy_kernel(X,X,math.atan2)
100 loops, best of 3: 7.84 ms per loop
In [489]: timeit K_vect(X[:,None],X)
100 loops, best of 3: 3.49 ms per loop
In [502]: timeit np.arctan2(X[:,None],X) # numpy compiled loop
1000 loops, best of 3: 871 µs per loop
def proxy_kernel(X,Y,K):
gram_matrix = np.zeros((X.shape[0], Y.shape[0]))
for i, x in enumerate(X):
for j, y in enumerate(Y):
gram_matrix[i, j] = K(x, y)
return gram_matrix
from numba import vectorize
@vectorize(['float64(float64, float64)'])
def K(x,y):
return x + y
a = np.arange(1000)
b = np.arange(1000)
gram_array = K(a[None,:], b[:, None])