在Numpy中应用无平凡的非平凡矩阵计算

时间:2019-04-01 16:53:49

标签: python arrays numpy matrix vectorization

只需尝试找到最佳方法即可为EM算法计算此更新的协方差矩阵 enter image description here *

我开发了算法,但是使用了for循环。我正在尝试确定如何利用Numpy向量化。

cov_c = []
for cluster, u, w in zip(r.T, mu_c, total_weight):
    s = 0
    for n in range(len(d)):
        s += cluster[n]*np.outer(d[n] - u, d[n] - u)
    cov_c.append(s / w)

cov_c是一个两个元素的列表,每个列表都有一个协方差矩阵(2x2)

    [array([[0.19, 0.23],[0.23, 0.39]]), 
     array([[4.05, -5.01,[-5.018,  6.22]])]

d和r均为二维数组(加权样本)d是特征向量(2个特征对应100个样本),其中r是2个高斯分布的每个特征的权重

d.shape
(100, 2)
r.shape
(100, 2)

mu_c是均值向量的两个元素列表

mu_c
[array([ 0.24387682, -0.27793324]), array([ 2.37853451, -1.86454301])]

总重量是归一化因子(仅2个元素的1d数组):

total_weight
array([53.51779102, 46.48220898])

关于如何向量化此计算的任何建议?谢谢!

1 个答案:

答案 0 :(得分:2)

我们可以利用NumPy数组来利用向量化ufunc操作。另外,由于d中的列数仅为2,因此我们将简单地沿该轴使用一个循环(因此只有两个迭代的循环)。因此,我们将使用切片数据,而不是在所有方向上扩展数组,这将导致更大的内存拥塞。我们仍将对切片的数据使用broadcasting。最后,我们将使用np.einsum来代替外部和的减少,这可能是我们获得最多收益的地方。

我们最终会得到这样的东西-

mu_c = np.asarray(mu_c)
total_weight = np.asarray(total_weight)

n = d.shape[1]
out = np.empty((n,2,2))
for i in range(n):
    du = d-mu_c[i]
    out[i] = np.einsum('i,ij,ik->jk',r[:,i],du,du)
cov_c_out = out/total_weight[:,None,None]

或者,该einsum部分可以用矩阵乘法步骤替换-

out[i] = (r[:,i,None]*du).T.dot(du)

出于完整性或乐趣的考虑,这是一个完全矢量化的解决方案,它占用大量内存,因此很可能较慢-

dmuc = d[:,None,:]-mu_c
out = np.einsum('ij,ijk,ijl->jkl',r,dmuc,dmuc)

另外,通过将其设置为optimize以使用BLAS,在np.einsum中使用True标志。