Этот ответ даст представление о том, что происходит, что приводит к особой ковариационной матрице во время подгонки GMM к набору данных, почему это происходит, а также о том, что мы можем сделать, чтобы предотвратить это.
Поэтому лучше всего начать с повторения этапов во время подгонки модели гауссовой смеси к набору данных.
0. Определите, сколько источников / кластеров (c) вы хотите разместить в своих данных.
1. Инициализируйте средние значения параметров , ковариацию Σ c и Fraction_per_class π c на кластер c.
μcΣcπc
E−Step–––––––––
- Рассчитать для каждой точки данных вероятностной г я гр что DataPoint х я принадлежу кластеру с с:
г я с = π с N ( х я | ц с , Σ с )xiricxi
гдеN(x|μ,Σ)описывает многовариантный гауссов с:
N(xi,μc,Σc)=1ric=πcN(xi | μc,Σc)ΣKk=1πkN(xi | μk,Σk)
N(x | μ,Σ)
ricдает нам для каждого элемента данныхxiмеру:ProbabilitythatхябелонгстослсN(xi,μc,Σc) = 1(2π)n2|Σc|12exp(−12(xi−μc)TΣ−1c(xi−μc))
ricxi , следовательноеслихяочень близко к одному гауссовой с, он будет получать высокуюRIсзначением для этого гауссова и относительно низкие значения в противном случае.
M-Step_
Для каждого кластера c: Рассчитать общий весmc.Probability that xi belongs to class cProbability of xi over all classesxiric
M−Step––––––––––
mc(условно говоря, доля точек, выделенных кластеру c) и обновите , µ c и Σ c, используя r i c, с помощью:
m c = Σ i r i c π c = m cπcμcΣcric
mc = Σiric
μc=1πc = mcm
Σc=1μc = 1mcΣiricxi
Помните, что вы должны использовать обновленные средства в этой последней формуле.
Итеративно повторяют Е и М шагпока функции логарифмического правдоподобия нашей модели сходитсягде журнал правдоподобия вычисляется с:
лпр(Х|П,ц,Σ)=Е N я = 1 лп(Е КΣc = 1mcΣiric(xi−μc)T(xi−μc)
ln p(X | π,μ,Σ) = ΣNi=1 ln(ΣKk=1πkN(xi | μk,Σk))
XAX=XA=I
[0000]
AXIΣ−1c0ковариационная матрица выше, если многовариантный гауссов попадает в одну точку во время итерации между этапами E и M. Это может произойти, если у нас есть, например, набор данных, к которому мы хотим вписать 3 гауссиана, но который на самом деле состоит только из двух классов (кластеров), так что, грубо говоря, два из этих трех гауссианов ловят свой кластер, а последний гауссиан управляет им только поймать одну единственную точку, на которой он сидит. Посмотрим, как это будет выглядеть ниже. Но шаг за шагом: предположим, что у вас есть двумерный набор данных, который состоит из двух кластеров, но вы этого не знаете и хотите подогнать к нему три гауссовых модели, то есть c = 3. Вы инициализируете свои параметры в шаге E и строите график гауссиане на вершине ваших данных, которые выглядят чем-то. например (возможно, вы можете видеть два относительно рассеянных кластера слева внизу и вверху справа):
μcπc
riccovric
ric=πcN(xi | μc,Σc)ΣKk=1πkN(xi | μk,Σk)
ricricxixixiricxiricря сΣс = Σ яря с( хя- μс)T( хя- μс)
ря сИкся( хя- μс)μсИксяJμJμJ= хNря с
[ 0000]
00матрица. Это делается путем добавления очень небольшого значения (в
GaussianMixture у
sklearn это значение равно 1e-6) к дигональному ковариационной матрицы. Существуют также другие способы предотвращения сингулярности, такие как уведомление о коллапсе гауссиана и установка его среднего значения и / или ковариационной матрицы на новое, произвольно высокое значение (я). Эта ковариационная регуляризация также реализована в приведенном ниже коде, с помощью которого вы получите описанные результаты. Возможно, вам придется запускать код несколько раз, чтобы получить единственную ковариационную матрицу, как уже было сказано. это не должно происходить каждый раз, но также зависит от первоначальной настройки гауссиан.
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')
from sklearn.datasets.samples_generator import make_blobs
import numpy as np
from scipy.stats import multivariate_normal
# 0. Create dataset
X,Y = make_blobs(cluster_std=2.5,random_state=20,n_samples=500,centers=3)
# Stratch dataset to get ellipsoid data
X = np.dot(X,np.random.RandomState(0).randn(2,2))
class EMM:
def __init__(self,X,number_of_sources,iterations):
self.iterations = iterations
self.number_of_sources = number_of_sources
self.X = X
self.mu = None
self.pi = None
self.cov = None
self.XY = None
# Define a function which runs for i iterations:
def run(self):
self.reg_cov = 1e-6*np.identity(len(self.X[0]))
x,y = np.meshgrid(np.sort(self.X[:,0]),np.sort(self.X[:,1]))
self.XY = np.array([x.flatten(),y.flatten()]).T
# 1. Set the initial mu, covariance and pi values
self.mu = np.random.randint(min(self.X[:,0]),max(self.X[:,0]),size=(self.number_of_sources,len(self.X[0]))) # This is a nxm matrix since we assume n sources (n Gaussians) where each has m dimensions
self.cov = np.zeros((self.number_of_sources,len(X[0]),len(X[0]))) # We need a nxmxm covariance matrix for each source since we have m features --> We create symmetric covariance matrices with ones on the digonal
for dim in range(len(self.cov)):
np.fill_diagonal(self.cov[dim],5)
self.pi = np.ones(self.number_of_sources)/self.number_of_sources # Are "Fractions"
log_likelihoods = [] # In this list we store the log likehoods per iteration and plot them in the end to check if
# if we have converged
# Plot the initial state
fig = plt.figure(figsize=(10,10))
ax0 = fig.add_subplot(111)
ax0.scatter(self.X[:,0],self.X[:,1])
for m,c in zip(self.mu,self.cov):
c += self.reg_cov
multi_normal = multivariate_normal(mean=m,cov=c)
ax0.contour(np.sort(self.X[:,0]),np.sort(self.X[:,1]),multi_normal.pdf(self.XY).reshape(len(self.X),len(self.X)),colors='black',alpha=0.3)
ax0.scatter(m[0],m[1],c='grey',zorder=10,s=100)
mu = []
cov = []
R = []
for i in range(self.iterations):
mu.append(self.mu)
cov.append(self.cov)
# E Step
r_ic = np.zeros((len(self.X),len(self.cov)))
for m,co,p,r in zip(self.mu,self.cov,self.pi,range(len(r_ic[0]))):
co+=self.reg_cov
mn = multivariate_normal(mean=m,cov=co)
r_ic[:,r] = p*mn.pdf(self.X)/np.sum([pi_c*multivariate_normal(mean=mu_c,cov=cov_c).pdf(X) for pi_c,mu_c,cov_c in zip(self.pi,self.mu,self.cov+self.reg_cov)],axis=0)
R.append(r_ic)
# M Step
# Calculate the new mean vector and new covariance matrices, based on the probable membership of the single x_i to classes c --> r_ic
self.mu = []
self.cov = []
self.pi = []
log_likelihood = []
for c in range(len(r_ic[0])):
m_c = np.sum(r_ic[:,c],axis=0)
mu_c = (1/m_c)*np.sum(self.X*r_ic[:,c].reshape(len(self.X),1),axis=0)
self.mu.append(mu_c)
# Calculate the covariance matrix per source based on the new mean
self.cov.append(((1/m_c)*np.dot((np.array(r_ic[:,c]).reshape(len(self.X),1)*(self.X-mu_c)).T,(self.X-mu_c)))+self.reg_cov)
# Calculate pi_new which is the "fraction of points" respectively the fraction of the probability assigned to each source
self.pi.append(m_c/np.sum(r_ic))
# Log likelihood
log_likelihoods.append(np.log(np.sum([k*multivariate_normal(self.mu[i],self.cov[j]).pdf(X) for k,i,j in zip(self.pi,range(len(self.mu)),range(len(self.cov)))])))
fig2 = plt.figure(figsize=(10,10))
ax1 = fig2.add_subplot(111)
ax1.plot(range(0,self.iterations,1),log_likelihoods)
#plt.show()
print(mu[-1])
print(cov[-1])
for r in np.array(R[-1]):
print(r)
print(X)
def predict(self):
# PLot the point onto the fittet gaussians
fig3 = plt.figure(figsize=(10,10))
ax2 = fig3.add_subplot(111)
ax2.scatter(self.X[:,0],self.X[:,1])
for m,c in zip(self.mu,self.cov):
multi_normal = multivariate_normal(mean=m,cov=c)
ax2.contour(np.sort(self.X[:,0]),np.sort(self.X[:,1]),multi_normal.pdf(self.XY).reshape(len(self.X),len(self.X)),colors='black',alpha=0.3)
EMM = EMM(X,3,100)
EMM.run()
EMM.predict()