判别式模型
本文主要通过Logistics Regression讲解判别式模型
由上文生成式模型的讲解,我们大致了解了生成式模型,首先通过假设某些条件求出了联合概率密度分布,再通过贝叶斯公式求出相应的分类概率。
判别式模型则是完全通过数据进行分析,没有任何人为的假设。
首先我们看一下上文中最后推出的后验概率:
此时我们令 \(z=ln\frac{P(x|blue)P(blue)}{P(x|green)P(green)}\),求出\(\frac{P(x|green)P(green)}{P(x|blue)P(blue)} = e^{-z}\)
带入\(P(blue|x)\)变为
学过的同学一看就知道这就是Logistics distribution。这个图像估计都看腻了,我就不讲解了。
目前的问题就是需要知道我们假设的 \(z\) 是什么样的。\(z=ln\frac{P(x|blue)P(blue)}{P(x|green)P(green)}\)。
此处我直接写出结论,不再进行推导了。说明一下如何推导,我们可以假设\(P(x|blue),P(x|green)\)服从某一种分布。将其分布带入到后验概率。即可求出
这种样式。(无论用哪种分布,都会得到这样的形式,这样就不要人为假设服从哪种分布了)
既然这样, 那我们直接将函数变为
目前我们的任务是如何求出 \(w,b\) 。我们只有样例数据,当然只能利用样例数据来求了。。那怎么求呢,因为数据有自变量取值,样例分类。—— 那我们就可以定义一个损失函数,利用梯度下降求出最优的 \(w,b\)
首先利用最大似然估计
遇到连乘的问题首先取 \(ln\) 变为连加。
目标函数变为:
为了好看,改一下:
接下来就可以利用梯度下降了。
此处用梯度下降
将\(H(w,b)\)代入可得
最终求得 \(w^{*}\) 和 \(b^{*}\)
迭代10000次得到的结果为
画出\(P(blue|x)\)的等高线可以看出在概率为0.5时还是能较好的分开两组数据
可以看出判别式模型中,完全是依据数据进行的分析,没有添加任何人为的假设(对于任意的分布\(z\)都满足\(z=wx+b\)的形式),直接根据贝叶斯后验概率进行的推导。
至此两种模型都讲完,这两者模型各有优缺点,当数据很少的时候,或许生成式模型中人为加入的限制更加有利于数据的分类,这会使得拟合效果更好。
附上代码:
# classification
# only use part[0] & part[1]
# @author Hongchuan CAO
# @date 2019-7-8
from sklearn import datasets
import numpy as np
import matplotlib.pyplot as plt
class SGD(object):
def __init__(self):
self.iris = datasets.load_iris()
self.part = [[], [], []]
def classify(self):
for i in range(len(self.iris.target)):
self.part[self.iris.target[i]].append(self.iris.data[i, :2])
# change list to array
for i in range(0, 3):
self.part[i] = np.array(self.part[i])
print(self.part[0][1])
def gradient(self):
w = np.array([1., 1.])
b = 4
learn_ratio = 0.001
iteration = 10000
for j in range(iteration):
sum_w = np.array([0., 0.])
sum_b = 0
for i in range(len(self.part[0])):
sum_w += (1.0 / (1 + np.exp(-1 * (np.dot(w, self.part[0][i].T) + b))) - 1) * self.part[0][i]
sum_b += (1.0 / (1 + np.exp(-1 * (np.dot(w, self.part[0][i].T) + b))) - 1)
for i in range(len(self.part[1])):
sum_w += (1.0 / (1 + np.exp(-1 * (np.dot(w, self.part[1][i].T) + b)))) * self.part[1][i]
sum_b += (1.0 / (1 + np.exp(-1 * (np.dot(w, self.part[1][i].T) + b))))
w = w - learn_ratio * sum_w / (len(self.part[0]) + len(self.part[1]))
b = b - learn_ratio * sum_b / (len(self.part[0]) + len(self.part[1]))
print(j, '-----------')
print(w,b)
return w, b
def ff(self, w, b, x):
return 1.0 / (1 + np.exp(-1 * (np.dot(w, x.T) + b)))
def plot1(self):
w, b = self.gradient()
xx = [x for x in np.arange(2, 8, 0.1)]
yy = [y for y in np.arange(1, 7, 0.1)]
Z = [[self.ff(w, b, np.array([x, y])) for x in xx] for y in yy]
X, Y = np.meshgrid(xx, yy)
cntr1 = plt.contourf(X, Y, Z)
plt.clabel(cntr1, colors='k', inline_spacing=3, fmt='%.1f', fontsize=10)
plt.plot(self.part[0][:, 0], self.part[0][:, 1], 'b.', label='0')
plt.plot(self.part[1][:, 0], self.part[1][:, 1], 'g.', label='1')
# plt.plot(self.part[2][:,0], self.part[2][:,1], 'r.', label='2')
plt.legend()
plt.xlabel('attribute0')
plt.ylabel('attribute1')
plt.show()
if __name__ == '__main__':
obj = SGD()
obj.classify()
obj.plot1()