只需尝试找到最佳方法即可为EM算法计算此更新的协方差矩阵 *
我开发了算法,但是使用了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])
关于如何向量化此计算的任何建议?谢谢!
答案 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
标志。