Python中的高效元素函数计算

时间:2015-05-06 19:54:24

标签: python numpy scikit-learn vectorization

我有以下优化问题。给定两个np.arrays XY和一个函数K我想尽可能快地计算矩阵入射gram_matrix,其中(i,j)-th元素计算为{{ 1}}。

这里有一个使用嵌套for循环的实现,它被认为是解决这类问题最慢的。

K(X[i],Y[j])

真的很感激任何帮助。

3 个答案:

答案 0 :(得分:1)

你肯定至少可以对内循环进行矢量化:

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

答案 1 :(得分:1)

np.vectorize确实在速度方面做了一些改进 - 大约2倍(这里我使用math.atan2作为带有2个标量参数的黑盒函数)。

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

只要K是黑匣子,就会受到KX.shape[0]*Y.shape[0]次调用所需时间的限制。您可以尝试最小化迭代时间,但仍然受到所有这些函数调用的限制。

https://stackoverflow.com/a/29733040/901925利用axis函数的np.linalg.norm参数,加速了Gausian内核的计算。

答案 2 :(得分:0)

您还可以尝试numba模块中的vectorize装饰器。

使用vectorize和numpy broadcasting

可以轻松解决您的特定问题
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])