将两个不同尺寸阵列的产品求和



我有兴趣可视化两个变量的loglikelihienhionhohienhionhohienhionh。

这是一个小代码:

import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as plt
#Generate fake data
x = np.random.normal(0,1,size = 100)
y = 2*x+1 + np.random.normal(size = x.size)
#Create a grid to visualize the log-likelihood
grid = np.linspace(-5,5,101)
B0,B1 = np.meshgrid(grid,grid)
#Compute the log likelihood
LogLik = 0
for xs,ys in zip(x,y):
    LogLik+= norm.logpdf(ys, loc = B0+B1*xs)
plt.contourf(B0,B1,LogLik)

这个小代码中的瓶颈是日志可能性的计算,即

for xs,ys in zip(x,y):
    LogLik+= norm.logpdf(ys, loc = B0+B1*xs)

如果x或y的长度很大,则需要比我所关心的更长的时间。有没有办法将分布平均值的创建(即B0+B1*xs)以及logpdf

进行评估。

这可以通过向数组广播新纳克斯来轻松矢量化。结果,瓶颈norm.logpdf只能执行一次:

log_lh = norm.logpdf(y, loc=B0[..., None] + B1[..., None] * x[None, None, :]).sum(axis=2)
# comparison with LogLik:
np.allclose(LogLik, log_lh)
# Out: True

将其重构为函数将允许执行时间:

def loglik(x, y, B0, B1):
    return norm.logpdf(y, loc=B0[..., None] + B1[..., None] * x[None, None, :]).sum(axis=2)
def loglik_loop(x, y, B0, B1):
    LogLik = 0
    for xs, ys in zip(x, y):
        LogLik+= norm.logpdf(ys, loc=B0+B1*xs)
%timeit loglik(x, y, B0, B1)
# Out: 94.1 ms ± 1.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit loglik_loop(x, y, B0, B1)
# Out: 54 ms ± 4.25 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

您可以看到,这似乎是极少数情况下的一种,其中矢量化代码不会改善性能。Scipy的norm模块中似乎还有另一个瓶颈,在多维数组上操作时,它会阻碍性能。

结果,提高代码性能的唯一可能性是实现循环的并行执行(替换+=操作员以分配给固定数组并求和之后)。

最新更新