我正在尝试定义一个包含内部循环以模拟积分的函数。
问题在于速度。在我的计算机上,评估该函数一次可能需要长达30秒的时间。由于我的最终目标是将该函数最小化,因此一些额外的速度会很不错。
因此,我尝试使用Cython来加速,但我肯定犯了严重的错误(可能有许多!)。按照Cython文档的指示,我尝试对变量进行类型定义。但是,在这样做之后,代码的速度与纯Python一样慢。这似乎很奇怪。
以下是我的代码:
import numpy as np
cimport cython
cimport numpy as np
import minuit
data = np.genfromtxt('q6data.csv', usecols = np.arange(1, 24, 1), delimiter = ',')
cdef int ns = 1000 # Number of simulation draws
cdef int K = 5 # Number of observed characteristics, including constant
cdef int J = len(data[:,1]) # Number of products, including outside
cdef double tol = 0.0001 # Inner GMM loop tolerance
nu = np.random.normal(0, 1, (6, ns)) # ns random deviates
@cython.boundscheck(False)
@cython.wraparound(False)
def S(np.ndarray[double, ndim=1] delta, double s1, double s2, double s3, double s4, double s5, double a):
"""Computes the simulated integrals, one for each good.
Parameters: delta is an array of length J containing mean product specific utility levels
Returns: Numpy array with length J."""
cdef np.ndarray[double, ndim=2] mu_ij = np.dot((data[:,2:7]*np.array([s1, s2, s3, s4, s5])), nu[1:K+1,:])
cdef np.ndarray[double, ndim=2] mu_y = a * np.log(np.exp(data[:,21].reshape(J,1) + data[:,22].reshape(J,1)*nu[0,:].reshape(1, ns)) - data[:,7].reshape(J,1))
cdef np.ndarray[double, ndim=2] V = delta.reshape(J,1) + mu_ij + mu_y
cdef np.ndarray[double, ndim=2] exp_vi = np.exp(V)
cdef np.ndarray[double, ndim=2] P_i = (1.0 / np.sum(exp_vi[np.where(data[:,1] == 71)], 0)) * exp_vi[np.where(data[:,1] == 71)]
cdef int yrs = 19
cdef int yr
for yr in xrange(yrs):
P_yr = (1.0 / np.sum(exp_vi[np.where(data[:,1]== (yr + 72))], 0)) * exp_vi[np.where(data[:,1] == (yr + 72))]
P_i = np.concatenate((P_i, P_yr))
cdef np.ndarray[double, ndim=1] S = np.zeros(dtype = "d", shape = J)
cdef int j
for j in xrange(ns):
S += P_i[:,j]
return (1.0 / ns) * S
def d_infty(np.ndarray[double, ndim=1] x, np.ndarray[double, ndim=1] y):
"""Sup norm."""
return np.max(np.abs(x - y))
def T(np.ndarray[double, ndim=1] delta_exp, double s1, double s2, double s3, double s4, double s5, double a):
"""The contraction operator. This function takes the parameters and the exponential
of the starting value of delta and returns the fixed point."""
cdef int iter = 0
cdef int maxiter = 200
cdef int i
for i in xrange(maxiter):
delta1_exp = delta_exp * (data[:, 8] / S(np.log(delta_exp), s1, s2, s3, s4, s5, a))
print i
if d_infty(delta_exp, delta1_exp) < tol:
break
delta_exp = delta1_exp
return np.log(delta1_exp)
def Q(double s1, double s2, double s3, double s4, double s5, double a):
"""GMM objective function."""
cdef np.ndarray[double, ndim=1] delta0_exp = np.exp(data[:,10])
cdef np.ndarray[double, ndim=1] delta1 = T(delta0_exp, s1, s2, s3, s4, s5, a)
delta1[np.where(data[:,10]==0)] = np.zeros(len(np.where(data[:,10]==0)))
cdef np.ndarray[double, ndim=1] xi = delta1 - (np.dot(data[:,2:7], np.linalg.lstsq(data[:,2:7], delta1)[0]))
cdef np.ndarray[double, ndim=2] g_J = xi.reshape(J,1) * data[:,11:21]
cdef np.ndarray[double, ndim=1] G_J = (1.0 / J) * np.sum(g_J, 0)
return np.sqrt(np.dot(G_J, G_J))
我已经对代码进行了分析,看起来是函数S,即积分模拟器,导致了性能问题。无论如何,我本来预期通过对变量进行输入会有一些速度上的提升。但是由于没有产生任何提升,我认为我可能犯了一些基本错误。
有没有人在Cython代码中看到可能导致这种结果的明显错误?
哦,由于我很新手,肯定有很多不好的风格和减慢代码速度的东西。如果你有时间,可以告诉我这些问题的正确方式。
data
有多大?你能把它分成若干块,其中第一列=={0,1,...18,71},并在内部循环之外进行吗? - denis