Estoy tratando de definir una función que contenga un bucle interno para simular una integral.Sin ganancias de velocidad de Cython
El problema es la velocidad. Evaluar la función una vez puede tomar hasta 30 segundos en mi máquina. Como mi objetivo final es minimizar esta función, una velocidad extra sería agradable.
Como tal, he tratado de hacer que Cython funcione, pero debo cometer un grave error (¡probablemente muchos de ellos!). Siguiendo la documentación de Cython, intenté escribir mis variables. Después de hacerlo, el código es tan lento como Python puro. Esto parece extraño.
Aquí está mi código:
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))
he perfilado el código, y que parece ser la función S, el simulador integral, que está matando el rendimiento. De todos modos, habría esperado al menos algunas ganancias de velocidad al escribir mis variables. Como no produjo ganancias, me hacen creer que estoy cometiendo algunos errores fundamentales.
¿Alguien ve un error evidente en el código de Cython que podría conducir a este resultado?
Ah, y como soy muy nuevo en la programación, seguramente hay un montón de malos estilos y cosas que ralentizan el código. Si tienes tiempo, no dudes en aclararme estos puntos también.
¿Qué tan grande es 'data'? ¿Podría dividirlo en pedazos donde la columna 1 == {0, 1, ... 18, 71} una vez, fuera del ciclo interno? – denis
Entonces los datos tienen 2237 filas y 21 columnas. Las filas se pueden dividir en subconjuntos correspondientes a los años desde 1971 hasta 1990.El obstáculo para mí ha sido encontrar una manera más rápida de hacer esa operación, ya que tengo que dividir cada entrada para un año determinado solo por la suma de las entradas correspondientes a ese año. Seguramente hay una mejor manera de lograr esto que lo que he implementado, ¡pero no lo he podido encontrar! –