Мы могли бы использовать массивы 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
в np.einsum
, установив его как True
для использования BLAS.