一、EM演算法
EM演算法是一種迭代演算法,用於含有隱含變數的機率模型引數的極大似然估計。設Y為觀測隨機變數的資料,Z為隱藏的隨機變數資料,Y和Z一起稱為完全資料。
觀測資料的似然函式為:
模型引數θ的極大似然估計為:
這個問題只有透過迭代求解,下面給出EM演算法的迭代求解過程:
step1、選擇合適的引數初值θ(0),開始迭代
step2、E步,求期望。θ(i)為第i次迭代θ的估計值,在第i+1步,計算下面的Q函式:
Q函式為logP(Y,Z|θ)關於在給定觀測資料Y和當前引數θ(i)下對隱藏變數Z的條件機率分佈P(Z|Y,θ(i))的期望。
step3、M步,求極大化。求使Q函式極大化的θ,確定第i+1次迭代的引數估計:
step4、重複第2、3步,直到收斂。
EM演算法對初值的選取比較敏感,且不能保證找到全域性最優解。
二、在高斯混合模型(GMM)中的應用
一維高斯混合模型:
多維高斯混合模型:
wk(k=1,2,……,K)為混合項係數,和為1。∑為協方差矩陣。θ=(wk,uk,σk)。
設有N個可觀測資料yi,它們是這樣產生的:先根據機率wk選擇第k個高斯分佈模型,生成觀測資料yi。yi是已知的,但yi屬於第j個模型是未知的,是隱藏變數。用Zij表示隱藏變數,含義是第i個資料屬於第j個模型的機率。先寫出完全資料的似然函式,然後確定Q函式,要最大化期望,對wk、uk、σk求偏導並使其為0。可得高斯混合模型引數估計的EM演算法(以高維資料為例):
step1、引數賦初始值,開始迭代
step2、E步,計算混合項係數Zij的期望 E[Zij]
:
step3、M步,計算新一輪迭代的引數模型:
step4、重複第2、3步,直到收斂。
前文搬運自連結:https://blog.csdn.net/u014157632/article/details/65442165
三、python程式示例
首先初始化分佈。
MU1 = [1 2];
SIGMA1 = [1 0; 0 0.5];
MU2 = [-1 -1];
SIGMA2 = [1 0; 0 1];
並用這兩個分佈各生成1000個散點。
點選檢視程式碼
import numpy as np
import matplotlib.pyplot as plt
from sklearn.mixture import GaussianMixture
# 初始化分佈引數
MU1 = np.array([1, 2])
SIGMA1 = np.array([[1, 0], [0, 0.5]])
MU2 = np.array([-1, -1])
SIGMA2 = np.array([[1, 0], [0, 1]])
# 生成資料點
data1 = np.random.multivariate_normal(MU1, SIGMA1, 1000)
data2 = np.random.multivariate_normal(MU2, SIGMA2, 1000)
X = np.concatenate([data1, data2]) # [2000, 2]
#對X進行隨機打亂,此步復現時不可忽略
np.random.shuffle(X)
接下來繪製二維散點圖。
點選檢視程式碼
plt.scatter(data1[:, 0], data1[:, 1], label='Class 1')
plt.scatter(data2[:, 0], data2[:, 1], label='Class 2')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Scatter Plot of Data Points')
plt.legend()
plt.show()
EM演算法實現高斯混合模型的擬合
點選檢視程式碼
import math
def fit_gaussian_mixture_model(X, n_components=2, max_iter=100):
# 合併資料
gmm = GaussianMixture(n_components=n_components, max_iter=max_iter)
gmm.fit(X)
return gmm.means_, gmm.covariances_, gmm.weights_
###擬合函式!
def my_fit_GMM(X, n_components=2, max_iter=1000):
# 給資料排序
n_samples, n_features = X.shape
X_SortIndex = np.lexsort((X[:, 0], X[:, 1]))
newArr = []
for id in X_SortIndex:
newArr.append(X[id])
X = np.array(newArr)
# 初始均值向量與協方差矩陣
mu = X[:n_components, :] # [n_components, n_features]
# cov = np.array(([[1.,0.],[0.,1.]],[[1.,0.],[0.,1.]]))
cov = np.ones(shape=(n_components, n_features, n_features)) # [n_components, n_features, n_features]
interval = n_samples // n_components
for i in range(n_components):
cov[i, ...] = np.cov(np.transpose(X[i*interval: (i+1)*interval, ...]))
mu[i, ...] = np.mean(X[i*interval: (i+1)*interval, ...], axis=0)
weights = np.ones(shape=(n_components, )) / n_components # [n_components, ]
# 直接編寫即可,不一定要使用結構體。
expectation = np.zeros(shape=(n_samples, n_components))
old_mu = np.copy(mu)
X = np.matrix(X)
mu = np.matrix(mu)
expectation = np.matrix(expectation)
for iteration in range(max_iter):
old_mu = np.copy(mu)
# 更新期望E
for i in range(n_samples):
for j in range(n_components):
expectation[i, j] = math.exp(-(X[i,:]-mu[j,:])*np.linalg.inv(cov[j,...])*np.transpose(X[i,:]-mu[j,:])/2)\
/ np.sqrt(np.linalg.det(cov[j,...]))
expectation[i, j] *= weights[j]
t = np.sum(expectation, axis=1).reshape(-1, 1)
expectation = expectation / t
# 更新模型(均值向量)
sum_E = np.zeros(shape=(n_components, ))
for j in range(n_components):
sum_E[j] = np.sum(expectation[:, j])
mu[j, ...] = np.sum(np.multiply(expectation[:, j], X), axis=0) / sum_E[j]
# 更新模型(協方差矩陣),混合項係數
for j in range(n_components):
cov_s = np.matrix(np.zeros((n_features, n_features)))
for i in range(n_samples):
cov_i = (X[i, ...] - mu[j, ...]).T * (X[i, ...] - mu[j, ...])
cov_s = cov_s + np.multiply(expectation[i, j], cov_i)
cov[j, ...] = np.array(cov_s) / sum_E[j]
weights[j] = sum_E[j] / n_samples
# 停止迭代的條件
if np.abs(np.linalg.det(old_mu - mu)) < 1e-6:
break
means = np.array(mu)
return means, cov, weights
# 請改為用my_fit_GMM擬合散點分佈。並輸出估計的均值,方差和混合項係數。
# means, cov, weights = fit_gaussian_mixture_model(X)
#
means, cov, weights = my_fit_GMM(X)
print("Data1.Means:")
print(means[0])
print("Data2.Means:")
print(means[1])
print("Data1.Covariances:")
print(cov[0])
print("Data2.Covariances:")
print(cov[1])
print("Weights:")
print(weights)
Data1.Means:
[-0.98994072 -0.99780233]
Data2.Means:
[1.00491397 1.98848228]
Data1.Covariances:
[[ 1.00762612 -0.04130926]
[-0.04130926 0.93607269]]
Data2.Covariances:
[[1.07037303 0.04512588]
[0.04512588 0.47164631]]
Weights:
[0.49222433 0.50777567]
點選檢視程式碼
#繪製結果的機率密度函式,用於驗證演算法效果
from scipy.stats import multivariate_normal
def draw_results(m,s,w):
# 定義兩個二維高斯分佈的引數
m1 = m[0]
s1 = s[0]
m2 = m[1]
s2 = s[1]
# 生成網格點
x, y = np.mgrid[-5:5:.01, -5:5:.01]
pos = np.dstack((x, y))
# 計算每個點的機率密度值
rv1 = multivariate_normal(m1, s1)
rv2 = multivariate_normal(m2, s2)
z1 = rv1.pdf(pos)
z2 = rv2.pdf(pos)
# 混合兩個高斯分佈的機率密度函式
z = w[0] * z1 + w[1] * z2 # 設定混合比例
# 繪製3D圖
fig = plt.figure(figsize=(5, 10))
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(x, y, z, cmap='viridis')
# 設定座標軸標籤和標題
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Probability Density')
ax.set_title('3D Plot of Mixture Gaussian Probability Density')
plt.show()
draw_results(means, cov, weights)
#看到擬合的視覺化結果了