逻辑回归
# 引入库文件方便后面用
import numpy as np
import matplotlib.pyplot as plt
1 线性回归
线性回归的模型是
h(w)=w0+w1x1+w2x2+⋯+wnxn=wTxh(w) = w^0 + w^1 x^1+w^2 x^2+\cdots+w^n x^n = \mathbf{w^Tx}h(w)=w0+w1x1+w2x2+⋯+wnxn=wTx
线性回归任务是找到一个超平面,使得该平面尽量能够代表给出的数据整体。其通常求θ\thetaθ和bbb的代价函数是
J(w)=∑i12(hw(xi)−yi)2J(w)=\sum_{i}\frac{1}{2}(h_w(x^i)-y^i)^2J(w)=i∑21(hw(xi)−yi)2
运用梯度下降方法更新
w:=w−α∂∂wJ(w)w:=w - \alpha \frac{\partial}{\partial w}J(w)w:=w−α∂w∂J(w)
只考虑第i个样本,对www求导推得
w:=w−α(yi−hw(xi))xiw:=w-\alpha(y^i-h_w(x^i))x^iw:=w−α(yi−hw(xi))xi
则批梯度下降(Batch Gradient Descent)可以描述成下式
Repeat until convergence{
w:=α∑i=1m(yi−hw(xi))xiw:=\alpha\sum_{i=1}^m(y^i-h_w(x^i))x^iw:=α∑i=1m(yi−hw(xi))xi (for every i)
}
通常批梯度下降当训练数据过大时,计算慢且耗内存,通常实际训练时用随机梯度下降 (Stochastic Gradient Descent)
Loop{
for i=1 to m,{
w:=w+α(yi−hw(xi))xiw:=w + \alpha(y^i-h_w(x^i))x^iw:=w+α(yi−hw(xi))xi (for every i)
}
}
2 逻辑回归
2.1 基本推导
线性回归是拟合问题,感知机是二分类问题,逻辑回归是二分类问题。但是逻辑回归能够通过sigmoid函数映射成某一类概率值。
# 画sigmoid
x = np.linspace(-10,10,100)
y = 1/(1 + np.exp(-x))
plt.plot(x,y)
plt.show()
逻辑回归模型为
y=σ(wTx+b), where σ(z)=11+e(−z)y=\sigma(w^Tx+b),\ where\ \sigma(z)=\frac {1} {1 + e^{(-z)}}y=σ(wTx+b), where σ(z)=1+e(−z)1
假设sigmoid函数σ(z)\sigma(z)σ(z)表示属于1类的概率,定义
p(y=1∣x;w)=σ(wTx+b)=σ(z)p(y=0∣x;w)=1−σ(z)p(y=1|x;w)=\sigma(w^Tx+b)=\sigma(z) \\ p(y=0|x;w)=1-\sigma(z)p(y=1∣x;w)=σ(wTx+b)=σ(z)p(y=0∣x;w)=1−σ(z)
用y^\hat{y}y^表示我们通过模型计算的值,即y^=σ(x)=11+e−(wx+b)\hat{y}=\sigma(x) = \frac{1}{1+e^{-(wx+b)}}y^=σ(x)=1+e−(wx+b)1 ,上述二式可以统一写成
p(y∣x)=y^y(1−y^)(1−y)p(y|x)=\hat{y}^y(1-\hat{y})^{(1-y)}p(y∣x)=y^y(1−y^)(1−y)
上式将分类为0和分类和1的概率计算公式合二为一。假设分类器分类足够准确,此时对于一个样本,如果它是属于1类,分类器求出的属于1类的概率应该尽可能大,即p(y=1∣x)p(y=1 | x)p(y=1∣x)尽可能接近1;如果它是0类,分类器求出的属于0类的概率应该尽可能大,即p(y=0∣x)p(y=0 | x)p(y=0∣x)尽可能接近1。
通过上述公式对二类分类的情况分析,可知我们的目的是求取参数w和b,使得p(y∣x)p(y|x)p(y∣x)对0类和1类的分类结果尽可能取最大值,然而实际上我们定义的代价函数的是求最小值,于是,很自然的,我们想到对p(y∣x)p(y|x)p(y∣x)式子加一个负号,就变成了求最小值的问题,这就得到了逻辑回归中的代价函数。为了方便计算两边取对数得
L(y^−y)=−logp(y∣x)=−ylogy^−(1−y)log(1−y^)L(\hat{y}-y)=-log p(y|x) = -y log\hat{y} - (1-y)log(1-\hat{y})L(y^−y)=−logp(y∣x)=−ylogy^−(1−y)log(1−y^)
对m个样本,则代价函数
J(w,b)=1m∑i=1mL(y^i−yi)J(w,b)=\frac {1}{m}\sum_{i=1}^m L(\hat{y}^i-y^i)J(w,b)=m1i=1∑mL(y^i−yi)
上式对www求偏导得
∂J∂w=1m∑i=1m(y^i−yi)xi\frac {\partial J}{\partial w} = \frac{1}{m}\sum_{i=1}^m(\hat{y}^i - y^i)x^i∂w∂J=m1i=1∑m(y^i−yi)xi
上式对bbb求偏导得
∂J∂b=1m∑i=1m(y^i−yi)\frac {\partial J}{\partial b} = \frac{1}{m}\sum_{i=1}^m(\hat{y}^i - y^i)∂b∂J=m1i=1∑m(y^i−yi)
如果只考虑一个样本的情况,运用链式法则,得
∂J∂w=(σ(x)−y)x\frac {\partial J}{\partial w} = (\sigma(x) - y)x∂w∂J=(σ(x)−y)x
∂J∂b=σ(x)−y\frac {\partial J}{\partial b} = \sigma(x) - y∂b∂J=σ(x)−y
所以迭代更新规则为
w:=w−α(σ(x)−y)xw := w - \alpha(\sigma(x) - y)xw:=w−α(σ(x)−y)x
b:=b−α(σ(x)−y)b := b - \alpha(\sigma(x) - y)b:=b−α(σ(x)−y)
至此,我们的推导就都完成了。另一种求w,b的方法是运用概率论中的极大似然估计,这里就不介绍了。下面我们用Python代码来实现一个简单的二维逻辑回归。
2.2 逻辑回归python实现
'''手动创造点数据'''
c1 = np.random.normal(3, 2, (2,100))
c1 = np.r_[c1, np.zeros((1, 100))] # 标签
c2 = np.random.normal(-3,2, (2,100))
c2 = np.r_[c2, np.ones((1, 100))] # 标签
# 将两类数据拼在一起并打乱样本顺序作为训练数据集
trainset = np.c_[c1,c2]
index = np.arange(200)
np.random.shuffle(index)
trainset = trainset[:,index]
'''初始化工作'''
w = np.zeros((2, 1)) # 初始化权值
b = 0 # 初始化
X = trainset[0:2,:].reshape(2,200) # 训练数据
Y = trainset[2,:].reshape(1,200) # 训练标签
m=200 # 样本数
alpha = 0.1 # 学习率
'''训练'''
for iter in range(100):
# 前向计算
Z = np.dot(w.T,X) + b
A = 1/(1 + np.exp(-Z))
# 反向传播
dz = A - Y
dw = (1/m)*np.dot(X,dz.T)
db = (1/m)*np.sum(dz)
# 更新
w = w - alpha*dw
b = b - alpha*db
'''画图'''
# 画原始图
p1 = plt.scatter(c1[0,:], c1[1,:], c='r', marker='o', s=15)
p2 = plt.scatter(c2[0,:], c2[1,:], c='b', marker='x', s=15)
# 画出直线
x1 = np.linspace(-10,10,100)
x2 = -(w[0]*x1 + b)/w[1]
plt.plot(x1, x2, c='g')
plt.legend([p1, p2], ["class 0", "class 1"], loc='upper left')
plt.title("Logistic Regression", fontsize=24)
plt.xlabel("dimension 1", fontsize=14)
plt.ylabel("dimension 2", fontsize=14)
plt.show()