首页 > 编程语言 >高斯混合模型(GMM)和EM算法 —— python实现

高斯混合模型(GMM)和EM算法 —— python实现

时间:2024-03-27 23:25:41浏览次数:33  
标签:EM ... GMM cov python expectation mu components np

一、EM算法

EM算法是一种迭代算法,用于含有隐含变量的概率模型参数的极大似然估计。设Y为观测随机变量的数据,Z为隐藏的随机变量数据,Y和Z一起称为完全数据。

观测数据的似然函数为:
image

模型参数θ的极大似然估计为:
image

这个问题只有通过迭代求解,下面给出EM算法的迭代求解过程:

step1、选择合适的参数初值θ(0),开始迭代

step2、E步,求期望。θ(i)为第i次迭代θ的估计值,在第i+1步,计算下面的Q函数:
image

Q函数为logP(Y,Z|θ)关于在给定观测数据Y和当前参数θ(i)下对隐藏变量Z的条件概率分布P(Z|Y,θ(i))的期望。

step3、M步,求极大化。求使Q函数极大化的θ,确定第i+1次迭代的参数估计:

step4、重复第2、3步,直到收敛。

EM算法对初值的选取比较敏感,且不能保证找到全局最优解。

二、在高斯混合模型(GMM)中的应用

一维高斯混合模型:
image

多维高斯混合模型:
image

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]
image

step3、M步,计算新一轮迭代的参数模型:
image

image

image

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()

image

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)
#看到拟合的可视化结果了

image

标签:EM,...,GMM,cov,python,expectation,mu,components,np
From: https://www.cnblogs.com/cjming/p/18100517

相关文章

  • 解决element-ui el-select数据过大方案
    一、背景项目中需要用到el-select选择医院,全国医院数据量非常大,通过API读取数据页面直接卡死。 二、解决方案1、组件:el-select+vue虚拟滚动(vue-virtual-scroll-list)2、安装:npminstallvue-virtual-scroll-list--save3、参考:NPM地址:https://www.npmjs.com/pack......
  • Python 函数
    目录函数自定义函数语法说明匿名函数语法模块标准库和扩展库中对象的导入与使用自定义函数的导入常用内置函数排序sorted()枚举enumerate()映射map()过滤filter()压缩zip()函数函数是可以重复使用的用于实现某种功能的代码块。在Python中,分内置函数......
  • 06-python异常和模块
    异常语法try:可能会错误的代码except:出现了异常,异常处理else:没有出现异常,处理,通常可以不写finally:无论有无异常,都运行实例:try:f=open("e:/a.txt","r",encoding="UTF-8")#文件不存在,不可度,会有异常exceptFileNotFoundErrorase:......
  • git clone 后如何 checkout 到 remote branch
    what/why通常情况使用gitclonegithub_repository_address下载下来的仓库使用gitbranch查看当前所有分支时只能看到master分支,但是想要切换到其他分支进行工作怎么办❓其实使用gitclone下载的repository没那么简单......
  • 头歌python循环结构答案
    Python中的循环结构,并提供一些常见的循环结构示例。在Python中,有两种主要的循环结构:`for`循环和`while`循环。###`for`循环`for`循环通常用于遍历序列(如列表、元组、字符串)或其他可迭代对象。**示例1:遍历列表中的元素**```pythonfruits=['apple','banana','cherry'......
  • Python循环结构程序设计 头歌python循环结构答案
    第2关:for循环与continue语句本关的编程任务是补全checkWork.py文件中的部分代码,具体要求如下:填入循环遍历studentname列表的代码;当遍历到缺席学生时,填入continue语句跳过此次循环。absencenum=int(input())studentname=[]inputlist=input()foriininputlist......
  • x64dbg破解EnableMenu.exe
    最近在学re,正好记录一下解题思路和x64dbg的使用。目录运行程序搜索API寻找调用者位置打上补丁方法一方法二运行程序首先运行exe文件,发现菜单中的Menue功能被禁用了,无法点击。所以,现在的目标就是修改程序,使菜单有效。搜索API由于该文件是32位的exe文件,所以应该......
  • WPF解决当ScrollViewer中嵌套ItemsControl时,不能使用鼠标来滚动翻页
    1.在DataGrid中添加PreviewMouseWheel事件,并将事件的Handled属性设置为false,以便将滚动事件传递给ScrollViewer。示例代码如下:<DataGridPreviewMouseWheel="DataGrid_PreviewMouseWheel"><!--DataGrid的其他设置--></DataGrid>privatevoidDataGrid_PreviewMouseWh......
  • 20231325贾罗祁 2023-2024-2《Python程序设计》实验二报告
    20231325贾罗祁2023-2024-2《Python程序设计》实验二报告课程:《Python程序设计》班级:2313姓名:贾罗祁学号:20231325实验教师:王志强实验日期:2024年3月27日必修/选修:公选课1.实验内容设计并完成一个完整的应用程序,完成加减乘除模等运算,功能多多益善;考核基本语法、判定......
  • 使用Python操作 xlsx 文件绘制雷达图原来这么简单!
    雷达图,听起来是不是很高大上?其实,它就是一种展示多维数据的可视化工具,形状像极了一个蜘蛛网,也被称为蜘蛛图或者星状图。最近我在做项目的时候,发现需要对多个指标进行综合评价,而雷达图正好能直观地展示出每个指标的优势和劣势。这样一来,我就可以更好地分析数据,找出问题的症结所......