GMM混合高斯模型的EM算法及Python实现

GMM(混合高斯模型)的EM算法

1.算法理论

p(x)=Kk=1πkN(x|μk,εk)

N(x|μk,εk)=1(2π)d|εk|exp(12(xiμk)Tε1k(xiμk))

Kk=1πk=1

用极大似然法处理问题:
输入:{ xi } (i = 1~N)
最小化:
E(πk,μk,εk)=Ni=1log[p(xi)]=

Ni=1log(Kk=11(2π)d|εk|exp(12(xiμk)Tε1k(xiμk)))

这是一个非凸问题,只能求局部极值,一般采用EM算法。
步骤如下:
1.随机化 πk,μk,εk
2.E步:计算

γn,k=πkN(xn|μk,εk)Kk=1N(xn|μk,εk)

上式表示:第n个样本落在第k个高斯的概率
3.M步:
Nk=Kk=1γn,k 表示N个样本中有多少属于第k个高斯
开始更新:
πnewk=NkN

μnewk=1NkNn=1γn,kxn

εnewk=1NkNn=1γn,k(xnμnewk)(xnμnewk)T

4.回到2直至收敛

python实现

代码基于

http://download.csdn.net/download/u012176591/8748673
在此基础上进行理解。

# 计算高斯函数
def Gaussian(data,mean,cov):
    dim = np.shape(cov)[0]   # 计算维度
    covdet = np.linalg.det(cov) # 计算|cov|
    covinv = np.linalg.inv(cov) # 计算cov的逆
    if covdet==0:              # 以防行列式为0
        covdet = np.linalg.det(cov+np.eye(dim)*0.01)
        covinv = np.linalg.inv(cov+np.eye(dim)*0.01)
    m = data - mean
    z = -0.5 * np.dot(np.dot(m, covinv),m)    # 计算exp()里的值
    return 1.0/(np.power(np.power(2*np.pi,dim)*abs(covdet),0.5))*np.exp(z)  # 返回概率密度值
# 用于判断初始聚类簇中的means是否距离离得比较近
def isdistance(means,criterion=0.03):
     K=len(means)
     for i in range(K):
         for j in range(i+1,K):
             if criterion>np.linalg.norm(means[i]-means[j]):
                 return False
     return True


# 获取最初的聚类中心
def GetInitialMeans(data,K,criterion):
    dim = data.shape[1]  # 数据的维度
    means = [[] for k in range(K)] # 存储均值
    minmax=[]
    for i in range(dim):
        minmax.append(np.array([min(data[:,i]),max(data[:,i])]))  # 存储每一维的最大最小值
    minmax=np.array(minmax)
    while True:
        for i in range(K):
            means[i]=[]
            for j in range(dim):
                 means[i].append(np.random.random()*(minmax[i][1]-minmax[i][0])+minmax[i][0] ) #随机产生means
            means[i]=np.array(means[i])

        if isdistance(means,criterion):
            break
    return means



# K均值算法,估计大约几个样本属于一个GMM
def Kmeans(data,K):
    N = data.shape[0]  # 样本数量
    dim = data.shape[1]  # 样本维度
    means = GetInitialMeans(data,K,15)
    means_old = [np.zeros(dim) for k in range(K)]
    # 收敛条件
    while np.sum([np.linalg.norm(means_old[k] - means[k]) for k in range(K)]) > 0.01:
        means_old = cp.deepcopy(means)
        numlog = [0] * K  # 存储属于某类的个数
        sumlog = [np.zeros(dim) for k in range(K)]
        # E步
        for i in range(N):
            dislog = [np.linalg.norm(data[i]-means[k]) for k in range(K)]
            tok = dislog.index(np.min(dislog))
            numlog[tok]+=1         # 属于该类的样本数量加1
            sumlog[tok]+=data[i]   # 存储属于该类的样本取值

        # M步
        for k in range(K):
            means[k]=1.0 / numlog[k] * sumlog[k]
    return means

def GMM(data,K):
    N = data.shape[0]
    dim = data.shape[1]
    means= Kmeans(data,K)
    convs=[0]*K
    # 初始方差等于整体data的方差
    for i in range(K):
        convs[i]=np.cov(data.T)
    pis = [1.0/K] * K
    gammas = [np.zeros(K) for i in range(N)]
    loglikelyhood = 0
    oldloglikelyhood = 1

    while np.abs(loglikelyhood - oldloglikelyhood) > 0.0001:
        oldloglikelyhood = loglikelyhood

        # E步
        for i in range(N):
            res = [pis[k] * Gaussian(data[i],means[k],convs[k]) for k in range(K)]
            sumres = np.sum(res)
            for k in range(K):           # gamma表示第n个样本属于第k个混合高斯的概率
                gammas[i][k] = res[k] / sumres
        # M步
        for k in range(K):
            Nk = np.sum([gammas[n][k] for n in range(N)])  # N[k] 表示N个样本中有多少属于第k个高斯
            pis[k] = 1.0 * Nk/N
            means[k] = (1.0/Nk)*np.sum([gammas[n][k] * data[n] for n in range(N)],axis=0)
            xdiffs = data - means[k]
            convs[k] = (1.0/ Nk)*np.sum([gammas[n][k]* xdiffs[n].reshape(dim,1) * xdiffs[n] for  n in range(N)],axis=0)
        # 计算最大似然函数
        loglikelyhood = np.sum(
            [np.log(np.sum([pis[k] * Gaussian(data[n], means[k], convs[k]) for k in range(K)])) for n in range(N)])

        print (means)
        print (loglikelyhood)
  • 6
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
GMM(Gaussian Mixture Model)是一种基于高斯分布的概率模型,常用于聚类或密度估计。EM(Expectation-Maximization)算法是一种迭代算法,通常用于GMM的参数估计。下面是使用Python实现GMMEM算法的示例代码: ``` import numpy as np from sklearn.mixture import GaussianMixture # 生成随机数据 np.random.seed(0) X = np.concatenate([np.random.randn(100, 2) + [2, 2], np.random.randn(100, 2) + [-2, -2], np.random.randn(100, 2) + [2, -2]]) # 初始化GMM模型 gmm = GaussianMixture(n_components=3, covariance_type='full') # 训练模型 gmm.fit(X) # 打印聚类结果 print(gmm.predict(X)) # 打印GMM模型参数 print('Means:') print(gmm.means_) print('Covariances:') print(gmm.covariances_) print('Weights:') print(gmm.weights_) ``` 这段代码使用了`sklearn.mixture.GaussianMixture`类,它可以方便地进行GMM模型的训练和参数估计。其中,`n_components`参数指定了聚类个数,`covariance_type`参数指定了协方差矩阵类型。在上面的例子中,我们使用了`'full'`类型,即完整协方差矩阵。 下面是使用Python实现EM算法的示例代码: ``` import numpy as np # 初始化参数 np.random.seed(0) K = 3 N = 300 mu = np.array([[-2, 2], [2, 2], [0, -2]]) sigma = np.array([[[1, 0], [0, 1]], [[1, 0.5], [0.5, 1]], [[0.5, 0], [0, 0.5]]]) alpha = np.ones(K) / K x = np.zeros((N, 2)) for i in range(K): x[i * 100:(i + 1) * 100, :] = np.random.multivariate_normal(mu[i, :], sigma[i, :, :], 100) # EM算法迭代 for t in range(10): # E步:计算后验概率 gamma = np.zeros((N, K)) for k in range(K): gamma[:, k] = alpha[k] * np.exp(-0.5 * np.sum((x - mu[k, :]) ** 2 / sigma[k, :, :], axis=1)) / np.sqrt(np.linalg.det(sigma[k, :, :])) gamma /= np.sum(gamma, axis=1, keepdims=True) # M步:更新模型参数 for k in range(K): Nk = np.sum(gamma[:, k]) mu[k, :] = np.sum(gamma[:, k].reshape(-1, 1) * x, axis=0) / Nk sigma[k, :, :] = np.sum(gamma[:, k].reshape(-1, 1, 1) * np.matmul((x - mu[k, :]).reshape(-1, 2, 1), (x - mu[k, :]).reshape(-1, 1, 2)), axis=0) / Nk alpha[k] = Nk / N # 打印模型参数 print('Iteration', t + 1) print('Means:') print(mu) print('Covariances:') print(sigma) print('Weights:') print(alpha) ``` 这段代码使用了EM算法来估计GMM模型的参数。其中,`mu`、`sigma`和`alpha`分别表示高斯分布的均值、协方差矩阵和权重,`gamma`表示后验概率。在每一轮迭代中,首先计算后验概率,然后根据后验概率更新模型参数。迭代结束后,打印出模型参数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值