【问题标题】:Vectorize this for loop in numpy在 numpy 中向量化这个 for 循环
【发布时间】:2017-10-06 11:06:07
【问题描述】:

我正在尝试使用 numpy 在 python 中计算矩阵 z(定义如下)。

这是我目前的解决方案(使用 1 for 循环)

z = np.zeros((n, k))
for i in range(n):
    v = pi * (1 / math.factorial(x[i])) * np.exp(-1 * lamb) * (lamb ** x[i])
    numerator = np.sum(v)
    c = v / numerator
    z[i, :] = c
return z

是否可以完全向量化这个计算?我需要为数千次迭代进行此计算,并且 numpy 中的矩阵运算比巨大的 for 循环快得多。

【问题讨论】:

  • 添加最小样例?
  • @Divakar 感谢您的评论。 This gist 可以作为例子(python3)。实现了一个EM算法,我想对E(x)函数进行矢量化。
  • lamb 不变吗?

标签: numpy


【解决方案1】:

这是E 的矢量化版本。它将for-loop 和标量算术替换为NumPy broadcasting 和基于数组的算术:

def alt_E(x):
    x = x[:, None]
    z = pi * (np.exp(-lamb) * (lamb**x)) / special.factorial(x)
    denom = z.sum(axis=1)[:, None]
    z /= denom
    return z

我运行em.py 来了解x、lamb、pi、n 和k 的典型大小。在这种大小的数据上, alt_E 比 E 快大约 120 倍:

In [32]: %timeit E(x)
100 loops, best of 3: 11.5 ms per loop

In [33]: %timeit alt_E(x)
10000 loops, best of 3: 94.7 µs per loop

In [34]: 11500/94.7
Out[34]: 121.43611404435057

这是我用于基准测试的设置:

import math
import numpy as np
import scipy.special as special

def alt_E(x):
    x = x[:, None]
    z = pi * (np.exp(-lamb) * (lamb**x)) / special.factorial(x)
    denom = z.sum(axis=1)[:, None]
    z /= denom
    return z


def E(x):
    z = np.zeros((n, k))
    for i in range(n):
        v = pi * (1 / math.factorial(x[i])) * \
            np.exp(-1 * lamb) * (lamb ** x[i])
        numerator = np.sum(v)
        c = v / numerator
        z[i, :] = c
    return z

n = 576
k = 2

x = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5])

lamb = np.array([ 0.84835141, 1.04025989])
pi = np.array([ 0.5806958, 0.4193042])

assert np.allclose(alt_E(x), E(x))

顺便说一句,E 也可以使用scipy.stats.poisson 计算:

import scipy.stats as stats
pois = stats.poisson(mu=lamb)

def alt_E2(x):
    z = pi * pois.pmf(x[:,None])
    denom = z.sum(axis=1)[:, None]
    z /= denom
    return z

但这并没有变得更快,至少对于这种长度的数组:

In [33]: %timeit alt_E(x)
10000 loops, best of 3: 94.7 µs per loop

In [102]: %timeit alt_E2(x)
1000 loops, best of 3: 278 µs per loop

对于较大的x,alt_E2 更快:

In [104]: x = np.random.random(10000)

In [106]: %timeit alt_E(x)
100 loops, best of 3: 2.18 ms per loop

In [105]: %timeit alt_E2(x)
1000 loops, best of 3: 643 µs per loop

【讨论】:

  • 你是真正的 MVP ;)
猜你喜欢
  • 2013-07-21
  • 2014-05-16
  • 1970-01-01
  • 2018-08-26
  • 2021-09-10
  • 2016-02-20
  • 1970-01-01
  • 2012-10-24
  • 1970-01-01
相关资源
最近更新 更多