Python 优化数学计算
我有一个购买一对商品的四种可能性的模型(同时购买、不购买或只购买一个),需要优化(伪)对数似然函数。当然,其中的一部分是伪对数似然函数的计算/定义 下面是我的代码,其中Beta是每个客户的二维向量(有U个客户和U个不同的Beta向量),X是每个项目的二维向量(N个项目中的每个项目不同),Gamma是对称矩阵,每对项目具有标量值Gamma(i,j)。df是一个购买的数据框架——每个客户一行,项目N列 在我看来,所有这些循环都是低效的,占用了太多的时间,但我不知道如何加快计算速度,如果有任何帮助,我将不胜感激。 提前谢谢你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列 在我看来,所有这些循环都是低效的,占用了太多的时间,但我不知道如何加快计算速度,如果有任何帮助,我
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。明天将更新