Python中高效的元素函数计算

Python中高效的元素函数计算,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

我有以下优化问题。给定两个np.array
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])