具有可变大小矩阵输入的Cython功能

时间:2014-04-01 07:30:20

标签: python numpy cython

我正在尝试将原生python函数的一部分转换为cython以改善计算时间。我想为占用时间的循环组件编写一个cython函数(正如ipython lprun告诉我的那样)。然而,这个函数采用了可变大小的矩阵..我无法看到如何将其轻松地转换为静态类型的cython。

for index1 in range(0,num_products):
    for index2 in range(0,num_products):
        cond_prob = (data[index1] * data[index2]).sum() / max(col_sums[index1], col_sums[index2])
        prox[index1][index2] = cond_prob

这个问题是num_products逐年变化,因此矩阵(数据)大小是可变的。

这里最好的策略是什么?

  1. 我应该写两个C函数吗?一个用memalloc创建一个特定维度的矩阵,然后用一个来创建矩阵的循环?
  2. 在这种情况下,是否有一些花哨的cython / numpy魔法帮助?我可以编写一个C函数,它在内存中采用可变大小的Numpy数组并传递大小吗?

2 个答案:

答案 0 :(得分:3)

Cython代码(策略性地)是静态类型的,但这并不意味着数组必须具有固定大小。在直接C中,将多维数组传递给函数可能会有点尴尬,但在Cython中,您应该能够执行以下操作:

注意我从follow-up question.

中获取了函数和变量名称
import numpy as np
cimport numpy as np
cimport cython

@cython.boundscheck(False)
@cython.cdivision(True)
def cooccurance_probability_cy(double[:,:] X):
    cdef int P, i, j, k
    P = X.shape[0]
    cdef double item
    cdef double [:] CS = np.sum(X, axis=1)
    cdef double [:,:] D = np.empty((P, P), dtype=np.float)

    for i in range(P):
        for j in range(P):
            item = 0
            for k in range(P):
                item += X[i,k] * X[j,k]
            D[i,j] = item / max(CS[i], CS[j])
    return D

另一方面,如果你使用正确的功能和一些广播,使用Numpy也应该很快解决这个问题。事实上,由于计算复杂性由矩阵乘法控制,我发现以下内容比上面的Cython代码快得多(np.inner使用高度优化的BLAS例程):

def new(X):
    CS = np.sum(X, axis=1, keepdims=True)
    D = np.inner(X,X) / np.maximum(CS, CS.T)
    return D

答案 1 :(得分:2)

你是否试过摆脱numpy中的for循环?

对于等式的第一部分,您可以尝试:

(data[ np.newaxis,:] * data[:,np.newaxis]).sum(2) 

如果内存有问题,您也可以使用np.einsum()函数。 对于第二部分,如果你还没有尝试过,那么你可能也会做出一个笨拙的表达(有点困难)。