生成学习算法

生成学习算法

可能大部分人之前学过的分类算法,都是基于train data来最佳化参数,从而得到data的类别。也就是基于p(y|x; θ)来进行学习,比如Logistic Regression。现在我们换一种思路,反过来求解,分别对p(x|y) 求解,也就是说,对每一个ymodel一个概率模型。当需要对新的data分类时,分别计算属于每个类的概率,从而得到最优的类别。公式基于贝叶斯定理,如下所示。


高斯线性判别

这个算法前提是p(x|y) 是基于多变量正态分布。多变量正态分布模型如下。

现在因为只有两种情况,y属于伯努利分布,然后分别对两种情况来model 多变量正态分布

对所有样本的几率和取对数,进行最大似然估计。

好,现在我们共有四个参数φ,Σ, μ0 ,μ1 。根据上面公式可分别求出四个参数。

到这里,高斯线性判别已经结束。我们分别对两个类型,进行拟合高斯模型。接下来需要分类的话,只需要对新的data分别用各自的高斯函数求解比较即可。具体的做法如下图。

GDA与Logistics回归

其实正好是一个相反的关系,当我们求解p(y = 1|x;φ,μ0,μ1,Σ)时,便是在求解Logistics回归,我们用上面的公式,并运用贝叶斯公式,即可得到Logistics回归的公式。

那么我们到底应该选用哪种算法?

大部分的情况下,Logistics回归的表现都会比GDA要好。因为GDA对数据分布模型依赖性很强。因为GDA的前提是p(x|y)是多变量正态分布的。当p(x|y)是多变量正态分布时,p(y|x)一定是Logistics回归的表现形式。然而反过来却不一定。也就是说GDA做了一个更强的假设。

朴素贝叶斯

朴素贝叶斯也是属于生成学习算法的一种。既然是属于生成学习算法,那我们的目标只有一个。那就是计算p(y|x)的概率,选取最大的那一类。理论还是和之前一样,使用贝叶斯公式,反过来计算。此处有个问题,若x是多维的应该如何计算。这里有一个强假设,就是说每一个特征的概率与其他概率是不相关的。这就是Naive Bayes (NB) assumption,这在实际生活中,当然是不可能的,但是即使如此,贝叶斯分类的效果依然是很好的。

在上面的公式中,我们其实只有三个参数,我们分别用 φi|y=1 = p(xi=1|y=1),φi|y=0 = p(xi=1|y=0)φy = p(y=1) 来表示。计算公式如下。

代码实现

下面给出一维的实现,多维其实一样的,只不过是把每一维都乘起来。粗粗一写,原谅不良的变量名,以及大量复制黏贴。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# 一维特征情况
train_data = [ {'Name':'Drew'},
{'Name':'Claudia'},
{'Name':'Drew'},
{'Name':'Drew'},
{'Name':'Alberto'},
{'Name':'Karin'},
{'Name':'Nina'},
{'Name':'Sergio'} ]
train_label = ['Male','Female','Female','Female','Male','Female','Female','Male']
predict_data = [{'Name':'Drew'}]
predict_label = None;
# 多维特征的情况
# train_data = [ {'Name':'Drew','Over170':'No','Eye':'Blue','Hair':'Short'},
# {'Name':'Claudia','Over170':'Yes','Eye':'Brown','Hair':'Long'},
# {'Name':'Drew','Over170':'No','Eye':'Blue','Hair':'Long'},
# {'Name':'Drew','Over170':'No','Eye':'Blue','Hair':'Long'},
# {'Name':'Alberto','Over170':'Yes','Eye':'Brown','Hair':'Short'},
# {'Name':'Karin','Over170':'No','Eye':'Blue','Hair':'Long'},
# {'Name':'Nina','Over170':'Yes','Eye':'Brown','Hair':'Short'},
# {'Name':'Sergio','Over170':'Yes','Eye':'Blue','Hair':'Long'} ]
# train_label = ['Male','Female','Female','Female','Male','Female','Female','Male']
# predict_data = [{'Name':'Drew','Over170':'Yes','Eye':'Blue','Hair':'Long'}]
# predict_label = None;
def predict(X, Y, predicted):
theta_y1 = 0 # φi|y=1
theta_y0 = 0 # φi|y=0
theta_y = 0 # φy
t1 = 0
t2 = 0
for i in range(len(X)):
if X[i]['Name'] == predict_data[0]['Name'] and Y[i] == predicted:
t1 += 1
if Y[i] == predicted:
t2 += 1
theta_y1 = t1 / t2
t1 = 0
t2 = 0
for i in range(len(X)):
if X[i]['Name'] == predict_data[0]['Name'] and Y[i] != predicted:
t1 += 1
if Y[i] != predicted:
t2 += 1
theta_y0 = t1 / t2
t1 = 0
t2 = 0
for i in range(len(X)):
if Y[i] == predicted:
t1 += 1
theta_y = t1 / len(X)
return (theta_y1, theta_y0, theta_y)
theta_y1, theta_y0, theta_y = predict(train_data, train_label, 'Male')
print(theta_y1 * theta_y / (theta_y1 * theta_y + theta_y0 * (1 - theta_y)))

Reference

CS229