期望最大化(EM)是一种概率分类方法。如果我错了,如果它不是一个分类器,请纠正我。
对这种EM技术的直观解释是什么?这里的expectation是什么?什么是maximized
发布于 2017-04-22 23:59:08
注意:此答案背后的代码可以在中找到。
假设我们从红色和蓝色两个不同的组中采样了一些数据:

在这里,我们可以看到哪个数据点属于红色或蓝色组。这使得很容易找到表征每一组的参数。例如,红色组的平均值约为3,蓝色组的平均值约为7(如果需要,我们可以找到确切的平均值)。
一般来说,这就是所谓的最大似然估计。给定一些数据,我们计算最能解释该数据的一个(或多个)参数的值。
现在想象一下,我们看不到哪个值是从哪个组中采样的。在我们看来,所有东西都是紫色的:

这里我们知道有两组值,但我们不知道任何特定的值属于哪一组。
我们仍然可以估计最适合这个数据的红色组和蓝色组的平均值吗?
是的,通常我们可以做到!Expectation 给了我们一种实现这一点的方法。该算法背后的基本思想是:
这些步骤需要进一步的解释,所以我将详细介绍上面描述的问题。
示例:估计均值和标准差
我将在本例中使用Python,但是如果您不熟悉这门语言,那么代码应该非常容易理解。
假设我们有两个组,红色和蓝色,其值分布如上图所示。具体地说,每个组包含一个从normal distribution中提取的值,该值具有以下参数:
import numpy as np
from scipy import stats
np.random.seed(110) # for reproducible results
# set parameters
red_mean = 3
red_std = 0.8
blue_mean = 7
blue_std = 2
# draw 20 samples from normal distributions with red/blue parameters
red = np.random.normal(red_mean, red_std, size=20)
blue = np.random.normal(blue_mean, blue_std, size=20)
both_colours = np.sort(np.concatenate((red, blue))) # for later use...下面是这些红色和蓝色组的图像(为了省去你滚动屏幕的麻烦):

当我们可以看到每个点的颜色(即它属于哪个组)时,很容易估计每个组的平均值和标准差。我们只是将红色和蓝色的值传递给NumPy中的内置函数。例如:
>>> np.mean(red)
2.802
>>> np.std(red)
0.871
>>> np.mean(blue)
6.932
>>> np.std(blue)
2.195但是如果我们看不到这些点的颜色呢?也就是说,每个点都被涂成了紫色,而不是红色或蓝色。
为了尝试恢复红色和蓝色组的平均值和标准差参数,我们可以使用期望最大化。
我们的第一步(上面的步骤1 )是猜测每组的平均值和标准差的参数值。我们不必聪明地猜测;我们可以选择任何我们喜欢的数字:
# estimates for the mean
red_mean_guess = 1.1
blue_mean_guess = 9
# estimates for the standard deviation
red_std_guess = 2
blue_std_guess = 1.7这些参数估计产生的钟形曲线如下所示:

这些都是错误的估计。例如,这两种方法(垂直虚线)看起来都远离任何类型的“中间”,例如,对于合理的点组。我们希望改进这些估计。
下一步(step 2)是计算每个数据点出现在当前参数猜测下的可能性:
likelihood_of_red = stats.norm(red_mean_guess, red_std_guess).pdf(both_colours)
likelihood_of_blue = stats.norm(blue_mean_guess, blue_std_guess).pdf(both_colours)在这里,我们简单地将每个数据点放入正态分布的probability density function中,使用我们目前对红色和蓝色的平均值和标准差的猜测。例如,这告诉我们,根据我们目前的猜测,1.761处的数据点更有可能是红色(0.189)而不是蓝色(0.00003)。
对于每个数据点,我们可以将这两个似然值转换为权重(step 3),以便它们的和为1,如下所示:
likelihood_total = likelihood_of_red + likelihood_of_blue
red_weight = likelihood_of_red / likelihood_total
blue_weight = likelihood_of_blue / likelihood_total使用我们当前的估计值和新计算的权重,我们现在可以计算红色和蓝色组的平均值和标准差的新估计值(步骤4)。
我们使用所有数据点计算两次平均值和标准差,但具有不同的权重:一次用于红色权重,一次用于蓝色权重。
直觉的关键点是,颜色在数据点上的权重越大,数据点对该颜色参数的下一次估计的影响就越大。这具有在正确的方向上“拉”参数的效果。
def estimate_mean(data, weight):
"""
For each data point, multiply the point by the probability it
was drawn from the colour's distribution (its "weight").
Divide by the total weight: essentially, we're finding where
the weight is centred among our data points.
"""
return np.sum(data * weight) / np.sum(weight)
def estimate_std(data, weight, mean):
"""
For each data point, multiply the point's squared difference
from a mean value by the probability it was drawn from
that distribution (its "weight").
Divide by the total weight: essentially, we're finding where
the weight is centred among the values for the difference of
each data point from the mean.
This is the estimate of the variance, take the positive square
root to find the standard deviation.
"""
variance = np.sum(weight * (data - mean)**2) / np.sum(weight)
return np.sqrt(variance)
# new estimates for standard deviation
blue_std_guess = estimate_std(both_colours, blue_weight, blue_mean_guess)
red_std_guess = estimate_std(both_colours, red_weight, red_mean_guess)
# new estimates for mean
red_mean_guess = estimate_mean(both_colours, red_weight)
blue_mean_guess = estimate_mean(both_colours, blue_weight)我们对参数有了新的估计。要再次改进它们,我们可以跳回步骤2并重复该过程。我们一直这样做,直到估计收敛,或者在执行了一定数量的迭代之后(step 5)。
对于我们的数据,这个过程的前五次迭代如下所示(最近的迭代具有更强的外观):

我们看到均值已经在某些值上收敛,曲线的形状(由标准差控制)也变得更加稳定。
如果我们继续迭代20次,我们将得到以下结果:

EM过程已经收敛到以下值,结果非常接近实际值(我们可以看到颜色-没有隐藏变量):
| EM guess | Actual | Delta
----------+----------+--------+-------
Red mean | 2.910 | 2.802 | 0.108
Red std | 0.854 | 0.871 | -0.017
Blue mean | 6.838 | 6.932 | -0.094
Blue std | 2.227 | 2.195 | 0.032在上面的代码中,您可能已经注意到,标准差的新估计是使用前一次迭代对平均值的估计来计算的。最终,如果我们首先计算平均值的新值,这并不重要,因为我们只是在某个中心点周围找到值的(加权)方差。我们仍然会看到参数的估计值收敛。
发布于 2012-08-05 04:09:39
EM是一种当模型中的一些变量未被观察到时(即当你有潜在变量时)最大化似然函数的算法。
你可能会问,如果我们只是试图最大化一个函数,为什么我们不使用现有的机制来最大化一个函数呢?如果你试图通过取导数并将其设置为零来最大化这个值,你会发现在许多情况下一阶条件没有解。要解决模型参数,需要知道未观测数据的分布;但未观测数据的分布是模型参数的函数,这是一个鸡和蛋的问题。
E-M试图通过迭代猜测未观测数据的分布来绕过这一问题,然后通过最大化实际似然函数的下限来估计模型参数,并重复直到收敛:
EM算法
从猜测模型参数值开始
E-step:对于每个有缺失值的数据点,使用您的模型方程来求解缺失数据的分布,给定您当前对模型参数的猜测和给定的观察数据(请注意,您正在求解每个缺失值的分布,而不是期望值)。现在我们有了每个缺失值的分布,我们可以计算关于未观察变量的似然函数的期望值。如果我们对模型参数的猜测是正确的,那么这个预期的可能性将是我们观察到的数据的实际可能性;如果参数不正确,它将只是一个下限。
M-step:现在我们已经有了一个没有未观测变量的预期似然函数,像在完全观测的情况下一样最大化该函数,以获得模型参数的新估计。
重复操作,直到收敛。
发布于 2013-07-11 23:11:03
这里有一个简单的方法来理解期望最大化算法:
1-由Do和Batzoglou读取此EM tutorial paper。
2-你可能脑子里有个问号,看看这个数学堆栈交换page上的解释。
Python3-看看我用写的这段代码,它解释了项目1的EM教程论文中的示例:
警告:由于我不是Python开发人员,所以代码可能会很混乱/不太理想。但它做到了这一点。
import numpy as np
import math
#### E-M Coin Toss Example as given in the EM tutorial paper by Do and Batzoglou* ####
def get_mn_log_likelihood(obs,probs):
""" Return the (log)likelihood of obs, given the probs"""
# Multinomial Distribution Log PMF
# ln (pdf) = multinomial coeff * product of probabilities
# ln[f(x|n, p)] = [ln(n!) - (ln(x1!)+ln(x2!)+...+ln(xk!))] + [x1*ln(p1)+x2*ln(p2)+...+xk*ln(pk)]
multinomial_coeff_denom= 0
prod_probs = 0
for x in range(0,len(obs)): # loop through state counts in each observation
multinomial_coeff_denom = multinomial_coeff_denom + math.log(math.factorial(obs[x]))
prod_probs = prod_probs + obs[x]*math.log(probs[x])
multinomial_coeff = math.log(math.factorial(sum(obs))) - multinomial_coeff_denom
likelihood = multinomial_coeff + prod_probs
return likelihood
# 1st: Coin B, {HTTTHHTHTH}, 5H,5T
# 2nd: Coin A, {HHHHTHHHHH}, 9H,1T
# 3rd: Coin A, {HTHHHHHTHH}, 8H,2T
# 4th: Coin B, {HTHTTTHHTT}, 4H,6T
# 5th: Coin A, {THHHTHHHTH}, 7H,3T
# so, from MLE: pA(heads) = 0.80 and pB(heads)=0.45
# represent the experiments
head_counts = np.array([5,9,8,4,7])
tail_counts = 10-head_counts
experiments = zip(head_counts,tail_counts)
# initialise the pA(heads) and pB(heads)
pA_heads = np.zeros(100); pA_heads[0] = 0.60
pB_heads = np.zeros(100); pB_heads[0] = 0.50
# E-M begins!
delta = 0.001
j = 0 # iteration counter
improvement = float('inf')
while (improvement>delta):
expectation_A = np.zeros((5,2), dtype=float)
expectation_B = np.zeros((5,2), dtype=float)
for i in range(0,len(experiments)):
e = experiments[i] # i'th experiment
ll_A = get_mn_log_likelihood(e,np.array([pA_heads[j],1-pA_heads[j]])) # loglikelihood of e given coin A
ll_B = get_mn_log_likelihood(e,np.array([pB_heads[j],1-pB_heads[j]])) # loglikelihood of e given coin B
weightA = math.exp(ll_A) / ( math.exp(ll_A) + math.exp(ll_B) ) # corresponding weight of A proportional to likelihood of A
weightB = math.exp(ll_B) / ( math.exp(ll_A) + math.exp(ll_B) ) # corresponding weight of B proportional to likelihood of B
expectation_A[i] = np.dot(weightA, e)
expectation_B[i] = np.dot(weightB, e)
pA_heads[j+1] = sum(expectation_A)[0] / sum(sum(expectation_A));
pB_heads[j+1] = sum(expectation_B)[0] / sum(sum(expectation_B));
improvement = max( abs(np.array([pA_heads[j+1],pB_heads[j+1]]) - np.array([pA_heads[j],pB_heads[j]]) ))
j = j+1https://stackoverflow.com/questions/11808074
复制相似问题