进行评估。
我有兴趣可视化两个变量的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
模块中似乎还有另一个瓶颈,在多维数组上操作时,它会阻碍性能。
结果,提高代码性能的唯一可能性是实现循环的并行执行(替换+=
操作员以分配给固定数组并求和之后)。