Otimizando cálculo matemático

votos
-2

Eu tenho um modelo de quatro possibilidades de comprar um par itens (compra de ambos, nenhum ou apenas um) e precisa otimizar o (pseudo-) log-verossimilhança função. Parte desta, naturalmente, é o cálculo / definição da função pseudo-log-probabilidade.

O seguinte é o meu código, onde Beta é um vetor 2-d para cada cliente (existem clientes U e vetores diferente beta U), X é um vetor 2-d para cada item (diferente para cada um dos itens N) e Gamma é uma matriz simétrica com uma gama valor escalar (i, j) para cada par de objectos. E df é uma trama de dados das compras - uma linha para cada cliente e N colunas para os itens.

Parece-me que todos estes laços são ineficientes e ocupam muito tempo, mas eu não estou certo de como acelerar este cálculo e gostaria de receber qualquer ajuda melhorá-lo. Agradeço antecipadamente!

def pseudo_likelihood(Args):
    Beta = np.reshape(Args[0:2*U], (U, 2))
    Gamma = np.reshape(Args[2*U:], (N,N))
    L = 0
    for u in range(0,U,1):
        print datetime.datetime.today(),  for user {}.format(u)
        y = df.loc[u][1:]
        beta_u = Beta[u,:]
        for l in range(N):
            print datetime.datetime.today(),  for item {}.format(l)
            for i in range(N-1):
                if i == l:
                    continue
                for j in range(i+1,N):
                    if (y[i] == y[j]):
                        if (y[i] == 1):
                            L += np.dot(beta_u,(x_vals.iloc[i,1:]+x_vals.iloc[j,1:])) + Gamma[i,j] #Log of the exponent of this expression
                        else:
                            L += np.log(
                                1 - np.exp(np.dot(beta_u, (x_vals.iloc[i, 1:] + x_vals.iloc[j, 1:])) + Gamma[i, j])
                                - np.exp(np.dot(beta_u, x_vals.iloc[i, 1:])) * (
                                            1 - np.exp(np.dot(beta_u, x_vals.iloc[j, 1:])))
                                - np.exp(np.dot(beta_u, x_vals.iloc[j, 1:])) * (
                                            1 - np.exp(np.dot(beta_u, x_vals.iloc[i, 1:]))))
                    else:
                        if (y[i] == 1):
                            L += np.dot(beta_u,x_vals.iloc[i,1:]) + np.log(1 - np.exp(np.dot(beta_u,x_vals.iloc[j,1:])))
                        else:
                            L += (np.dot(beta_u, x_vals.iloc[j,1:])) + np.log(1 - np.exp(np.dot(beta_u, x_vals.iloc[i,1:])))

            L -= (N-2)*np.dot(beta_u,x_vals.iloc[l,1:])
            for k in range(N):
                if k != l:
                    L -= np.dot(beta_u, x_vals.iloc[k,1:])

    return -L

Para adicionar / esclarecer - Estou usando este cálculo para otimizar e encontrar os parâmetros beta e gama que geraram os dados para esta função pseudo-verossimilhança.
Eu estou usando optimize.minimize scipy com o método do 'Powell'.

Publicado 08/11/2018 em 06:51
fonte usuário
Em outras línguas...                            


1 respostas

votos
0

Atualizando para quem está interested- achei numpy.einsum para acelerar os cálculos aqui por mais de 90%.

np.einsum executa operações de matriz / vector utilizando a notação Einstein. Recorde-se que para duas matrizes A, B seu produto pode ser representado como a soma de

a_ij*b_jk

ou seja, o elemento ik da matriz AB é a soma ao longo j de a_ij * b_jk

Usando a função einsum eu poderia calcular antecipadamente todos os valores necessários para o cálculo iterativo, economizando tempo precioso e centenas, se não milhares, de cálculos desnecessários. Eu reescrevi o código da seguinte forma:

def pseudo_likelihood(Args):
    Beta = np.reshape(Args[0:2*U], (U,2))
    Gamma = np.reshape(Args[2*U:], (N,N))
    exp_gamma = np.exp(Gamma)
    L = 0
    for u in xrange(U):
        y = df.loc[u][1:]
        beta_u = Beta[u,:]
        beta_dot_x = np.einsum('ij,j',x_vals[['V1','V2']],beta_u)
        exp_beta_dot_x = np.exp(beta_dot_x)
        log_one_minus_exp = np.log(1 - exp_beta_dot_x)
        for l in xrange(N):
            for i in xrange(N-1):
                if i == l:
                    continue
                for j in xrange(i+1,N):
                    if (y[i] == y[j]):
                        if (y[i] == 1):
                            L += beta_dot_x[i] + beta_dot_x[j] + Gamma[i,j] #Log of the exponent of this expression
                        else:
                            L += math.log(
                                1 - exp_beta_dot_x[i]*exp_beta_dot_x[j]*exp_gamma[i,j]
                                - exp_beta_dot_x[i] * (1 - exp_beta_dot_x[j])
                                - exp_beta_dot_x[j] * (1 - exp_beta_dot_x[i]))
                    else:
                        if (y[i] == 1):
                            L += beta_dot_x[i] + log_one_minus_exp[j]
                        else:
                            L += (beta_dot_x[j]) + log_one_minus_exp[i]

            L -= (N-2)*beta_dot_x[l]
            for k in xrange(N):
                if k != l:
                    L -= sum(beta_dot_x) + beta_dot_x[l]

    return -L
Respondeu 15/11/2018 em 09:59
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more