Python 优化数学计算

Python 优化数学计算,python,optimization,scipy,mathematical-optimization,numpy-einsum,Python,Optimization,Scipy,Mathematical Optimization,Numpy Einsum,我有一个购买一对商品的四种可能性的模型(同时购买、不购买或只购买一个),需要优化(伪)对数似然函数。当然,其中的一部分是伪对数似然函数的计算/定义 下面是我的代码,其中Beta是每个客户的二维向量(有U个客户和U个不同的Beta向量),X是每个项目的二维向量(N个项目中的每个项目不同),Gamma是对称矩阵,每对项目具有标量值Gamma(i,j)。df是一个购买的数据框架——每个客户一行,项目N列 在我看来,所有这些循环都是低效的,占用了太多的时间,但我不知道如何加快计算速度,如果有任何帮助,我

我有一个购买一对商品的四种可能性的模型(同时购买、不购买或只购买一个),需要优化(伪)对数似然函数。当然,其中的一部分是伪对数似然函数的计算/定义

下面是我的代码,其中Beta是每个客户的二维向量(有U个客户和U个不同的Beta向量),X是每个项目的二维向量(N个项目中的每个项目不同),Gamma是对称矩阵,每对项目具有标量值Gamma(i,j)。df是一个购买的数据框架——每个客户一行,项目N列

在我看来,所有这些循环都是低效的,占用了太多的时间,但我不知道如何加快计算速度,如果有任何帮助,我将不胜感激。 提前谢谢你

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
添加/澄清-我使用此计算优化并找到生成此伪似然函数数据的beta和gamma参数。

我正在使用scipy optimize.minimize和“Powell”方法。

为感兴趣的人更新- 我发现numpy.einsum可以将这里的计算速度提高90%以上

np.einsum使用爱因斯坦表示法执行矩阵/向量运算。回想一下,对于两个矩阵A、B,它们的乘积可以表示为

a_ij*b_jk
i、 e.矩阵AB的ik元素是a_ij*b_jk在j上的和

使用einsum函数,我可以提前计算迭代计算所需的所有值,从而节省宝贵的时间和成百上千的不必要计算。 我将代码改写如下:

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

您能否提供一个完整的工作示例(包括所有Variables的实际大小的数据)?由于python在for循环方面的速度非常慢,如果您能够将一些循环转换为可以在机器代码中固有运行的函数,您可能也会受益匪浅。即,查看
numba
库并添加decorator
@jit(nopython=True)
@Attack68非常感谢;不幸的是,numba不支持pandas,也不支持我的代码。我知道,我提出的观点(相当不明确)是,不要试图将装饰器放在函数的顶部,希望它能工作,因为它不会,而是尝试对函数进行子分析,并将其分解为子循环所在的块(仅使用NumPy)可以提取并重新配制。虽然说你只在一行中使用一个熊猫数据帧,而且可以很容易地转换成一个NumPy数组,我明白了。谢谢,我不明白。我将看看是否可以隔离numpy代码块并适当地添加decorator。明天将更新