【问题标题】:Optimizing Mathematical Calculation优化数学计算
【发布时间】:2019-04-11 15:59:21
【问题描述】:

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

以下是我的代码,其中 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' 方法。

【问题讨论】:

  • 您能否提供一个完整的工作示例(包括所有变量的实际大小数据)?

标签: python optimization scipy mathematical-optimization numpy-einsum


【解决方案1】:

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

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

a_ij*b_jk

即矩阵 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

【讨论】:

  • 由于 python 的 for 循环非常慢,如果您可以将一些循环转换为可以在机器代码中固有运行的函数,您可能也会受益匪浅。 IE。查看numba 库并添加装饰器@jit(nopython=True)
  • @Attack68 非常感谢;不幸的是 numba 不支持 pandas 并且不适用于我的代码
  • 是的,我知道,我提出的观点(相当不清楚)是,与其试图将装饰器放在函数的顶部并希望它有效,因为它不会,尝试对您的函数进行子分析并将其分解为可以提取和重新制定子循环(仅使用 NumPy)的块。虽然说你只在一行中使用了 pandas 数据框,并且可以很容易地转换为 NumPy 数组。
  • 我明白了。谢谢,我没看懂。我会看看我是否可以隔离 numpy 代码块并适当地添加装饰器。明天更新
猜你喜欢
  • 2012-09-03
  • 1970-01-01
  • 1970-01-01
  • 2015-02-04
  • 2020-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-19
相关资源
最近更新 更多