In [1]:
import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import cholesky, solve_triangular
from scipy.special import logsumexp
In [2]:
def random_choice(X):
arr = range(len(X))
idx = np.random.choice(arr)
return X[idx]
In [3]:
def compute_prec_chol(cov):
_, p = np.array(cov).shape
cov_chol = cholesky(cov, lower=True)
return solve_triangular(cov_chol, np.eye(p), lower=True).T
In [54]:
def compute_mahalanobis(X, mu, prc_chol):
y = np.dot(X, prc_chol) - np.dot(mu, prc_chol)
return np.sum(np.square(y), axis=1)
In [168]:
np.random.seed(0)
In [169]:
X1 = np.c_[np.random.randn(200), np.random.randn(200)]
X2 = np.c_[np.random.randn(200)*.5 + 1, np.random.randn(200)*.5 + 1]
X = np.r_[X1, X2]
X[:5]
Out[169]:
In [72]:
plt.scatter(X1[:,0], X1[:,1], alpha=.5, c='b')
plt.scatter(X2[:,0], X2[:,1], alpha=.5, c='r')
plt.show()
In [132]:
mu01 = random_choice(X)
cov01 = np.cov(X.T)
mu02 = random_choice(X)
cov02 = np.cov(X.T)
print 'initial guesses'
print 'mu01: {0}\ncov01: {1}'.format(mu01, cov01)
print '\nmu02: {0}\ncov02: {1}'.format(mu02, cov02)
In [133]:
tau = np.random.rand(*X.shape)
tau = tau / tau.sum(1)[:, np.newaxis]
tau[:5]
Out[133]:
In [158]:
_, p = X.shape
# e-step
prc_chol = compute_prec_chol(cov01)
log_det = np.log(prc_chol.reshape(1, -1)[:,::p+1]).sum()
mahalanobis = compute_mahalanobis(X, mu01, prc_chol)
tau01 = -p*.5*np.log(2 * np.pi) + log_det -.5*mahalanobis
prc_chol = compute_prec_chol(cov02)
log_det = np.log(prc_chol.reshape(1, -1)[:,::p+1]).sum()
mahalanobis = compute_mahalanobis(X, mu02, prc_chol)
tau02 = -p*.5*np.log(2 * np.pi) + log_det -.5*mahalanobis
tau = np.c_[tau01, tau02] + np.log(tau.sum(axis=0))
log_resp = tau - logsumexp(tau, axis=1)[:, np.newaxis]
print log_resp[:10]
In [115]:
tau = np.exp(log_resp)
mu01 = np.dot(tau[:,0], X) / np.sum(tau, 0)[:, np.newaxis][0]
mu02 = np.dot(tau[:,1], X) / np.sum(tau, 0)[:, np.newaxis][1]
diff = X - mu01
cov01 = np.dot(tau[:, 0] * diff.T, diff) / np.sum(tau, 0)[:, np.newaxis][0]
diff = X - mu02
cov02 = np.dot(tau[:, 1] * diff.T, diff) / np.sum(tau, 0)[:, np.newaxis][1]
print 'mu01: {0}\ncov01: {1}'.format(mu01, cov01)
print '\nmu02: {0}\ncov02: {1}'.format(mu02, cov02)
In [76]:
def compute_prec_chol(cov):
_, p = np.array(cov).shape
cov_chol = cholesky(cov, lower=True)
return solve_triangular(cov_chol, np.eye(p), lower=True).T
In [40]:
def compute_precs_chol(covs):
_, p, p = np.array(covs).shape
precs_chol = np.empty((n_components, p, p))
for k, cov in enumerate(covs):
cov_chol = cholesky(cov, lower=True)
precs_chol[k] = solve_triangular(cov_chol, np.eye(p), lower=True).T
return precs_chol
In [167]:
def e_step(X, tau, mus, covs):
n_samples, p = X.shape
prc_chols = compute_precs_chol(covs)
log_det = np.log(prc_chols.reshape(n_components, -1)[:,::p+1]).sum(axis=1)
log_prob = np.empty((n_samples, n_components))
for k, (mu, prc_chol) in enumerate(zip(mus, prc_chols)):
log_prob[:, k] = compute_mahalanobis(X, mu, prc_chol)
weighted_log = .5*(-p * np.log(2 * np.pi) - log_prob) + log_det + np.log(tau.sum(axis=0))
log_resp = weighted_log - logsumexp(weighted_log, axis=1)[:, np.newaxis]
return log_resp
In [185]:
n_components = 2
mu = np.c_[random_choice(X), random_choice(X)].T
cov = np.r_[np.cov(X.T), np.cov(X.T)].reshape(2, 2, -1)
tau = np.random.rand(*X.shape)
tau = tau / tau.sum(1)[:, np.newaxis]
tau[:5]
Out[185]:
In [186]:
print 'initial guesses'
print 'mu: {0}\ncov: {1}'.format(mu, cov)
In [187]:
_, p = X.shape
bottom = -np.inf
l = []
for _ in range(100):
prev = bottom
log_resp = e_step(X, tau, mu, cov)
tau = np.exp(log_resp)
mu = np.dot(tau.T, X) / np.sum(tau, 0)[:, np.newaxis]
pi = np.sum(tau, 0)[:, np.newaxis]
cov = np.empty((n_components, p, p))
for k, _ in enumerate(mu):
diff = X - _
cov[k] = np.dot(tau[:, k] * diff.T, diff) / pi[k]
bottom = np.mean(log_resp)
l.append(bottom)
if abs(bottom - prev) < 1e-4:
break
In [188]:
print 'mu: {0}\ncov: {1}'.format(mu, cov)
In [189]:
arr = range(len(l))
plt.scatter(arr, l)
plt.show()
In [65]:
pi = np.sum(tau, 0)[:, np.newaxis]
cov = np.empty((n_components, p, p))
for k, _ in enumerate(mu):
diff = X - _
cov[k] = np.dot(tau[:, k] * diff.T, diff) / pi[k]
Out[65]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]:
In [ ]: