逻辑回归(LR)
线性模型
基本概念
给定一个由d个属性决定的示例$x=(x_{1},x_{2},...)$,线性模型试图学得一个通过属性的线性组合来预测的函数,即
$$f(x)=w_{1}x_{1}+w_{2}x_{2}+...+w_{d}x_{d}+b$$
也可以写成向量形式
$$f(x)=w^{T}x+b$$
其中$w=(w_{1},w_{2},...)$,而$w$与$b$确定后,模型就得以确定
线性回归
针对确定$w$与$b$,均方误差是回归任务中最常用的性能度量,因此我们可以使均方误差最小化,针对函数
$$f(x_{i})=wx_{i}+b$$
我们希望
$$J(w,b)=\frac{1}{2}\sum_{i=1}^{m}(f(x_{i})-y)^{2}$$
得到最小值,即$$f(x_{i})\approx y_{i}$$
我们一般直接将b化为w的一部分,然后对w求偏导得
$$\frac{\partial J}{\partial w}=\sum_{i=1}^{m}(f(x_{i})- y_{i})*x_{i}$$
对于单w来说可以通过导数等于0得到其最优解,但是针对多属性函数,则需要使用梯度下降方法得到其全局最优解,梯度下降的具体推导需要使用多元泰勒展开,此不赘述,要记住梯度的计算,即
$$\nabla f(w_{1},w_{2},...)=(\frac{\partial f}{\partial w_{1}},\frac{\partial f}{\partial w_{2}},...)$$
而梯度下降的数学公式则是
$$w_{t+1}=w_{t}-\eta*\nabla f(w_{t})$$
其中$\eta$代表学习率,一般我们使用$\eta=\frac{\eta}{t+1}+a$来防止步长过大和过小,通过迭代后我们可以获得我们想要的$w$值
对数回归
Sigmoid函数
它的作用是将线性的z值转化为接近0或1的y值
$$y=\frac{1}{1+e^{-z}}$$
其特殊之处在于
$$\frac{\partial f}{\partial z}=f(z)*(1-f(z))$$
数学推导
若将y视为x作为正例的可能性,1-y是其反例的可能性,两者比值为
$$\frac{y}{1-y}$$
称为几率,将其取对数后可以得到
$$ln\frac{P(y=1|x)}{P(y=0|x)}=w^Tx+b$$
定义似然函数为
$$L(w)=\prod_{m}^{i=1}{P(y^{(i)}=1|x^{(i)})^{(y^{(i)})}·P(y^{(i)}=0|x^{(i)})^{(1-y^{(i)})}}$$
为简便书写,令
$$P(y^{(i)}=1|x^{(i)}) = h_{w}(x^{(i)})$$
则似然函数则是
$$L(w)=\prod_{m}^{i=1}{h_{w}(x^{(i)}))^{y^{(i)}}·(1-h_{w}(x^{(i)}))^{1-y^{(i)}}}$$
采取对数似然
$$log(l(w))=-\sum_{i=1}^{m}{[y_{i} log h_{w}(x^{(i)})+(1−y_{i})log(1−h_{w}(x^{(i)})]}$$
再令
$$J(w)=log(l(w))$$
再对其求偏导得
$$\frac{\partial J}{\partial w}=-\sum_{i=1}^{m}{(y^{(i)}-h_{w}(x^{(i)}))x^{(i)}_{j} }$$
小结
至此你会发现逻辑回归和线性回归的拉普拉斯算子得到的是一样的,当然可能是巧合吧(至于是不是得靠数学推导),接下来会说明多种梯度下降算法
梯度下降
正常的梯度下降中梯度计算如下
$$\nabla{J(x)}=\frac{1}{n}\nabla\sum_{i=1}^{n}{J(x_i)}$$
如果使用梯度下降法(批量梯度下降法),那么每次迭代过程中都要对$n$个样本进行求梯度,所以开销非常大,随机梯度下降的思想就是随机采样一个样本$J(x_{i})$来更新参数,那么计算开销就从$\mathcal{O}{(n)}$下降到$\mathcal{O}{(1)}$ 。
其中更新公式如下
批量梯度下降

随机梯度下降

相关代码
#梯度下降
def gradacent(inputdata, inputlable):
datamat = np.mat(inputdata)
lablemat = np.mat(inputlable).transpose()
m, n = np.shape(datamat)
alpha = 0.001
cycle = 500
weights = np.ones((n, 1))
for k in range(cycle):
h = sigmoid(datamat * weights)
error = h - lablemat
weights = weights - alpha * datamat.transpose() * error #核心
return weights
#随机梯度下降
def randomgradacent(inputdata, inputlable, numiter=150):
datamat = np.array(inputdata)
m, n = np.shape(datamat)
weights = np.ones((1, n))
for j in range(numiter):
dataindex = list(range(m))
for k in range(m):
alpha = 4 / (1.0 + j + k) + 0.01
randindex = int(random.uniform(0, len(dataindex)))
h = sigmoid(np.dot(datamat[randindex], weights.transpose()))
error = h - inputlable[randindex]
weights = weights - alpha * error * datamat[randindex] #核心
del (dataindex[randindex])
return weights.transpose()
代码
import numpy as np
import random
def loaddata():
data = []
lable = []
with open('testSet.txt') as fr:
while True:
line = fr.readline()
if line:
linearr = line.strip().split()
data.append([1.0, float(linearr[0]), float(linearr[1])])
lable.append(int(linearr[2]))
else:
break
pass
return data, lable
def sigmoid(x):
return 1.0 / (1 + np.exp(-x))
def gradacent(inputdata, inputlable):
datamat = np.mat(inputdata)
lablemat = np.mat(inputlable).transpose()
m, n = np.shape(datamat)
alpha = 0.001
cycle = 500
weights = np.ones((n, 1))
for k in range(cycle):
h = sigmoid(datamat * weights)
error = h - lablemat
weights = weights - alpha * datamat.transpose() * error
return weights
def randomgradacent(inputdata, inputlable, numiter=150):
datamat = np.array(inputdata)
m, n = np.shape(datamat)
weights = np.ones((1, n))
for j in range(numiter):
dataindex = list(range(m))
for k in range(m):
alpha = 4 / (1.0 + j + k) + 0.01
randindex = int(random.uniform(0, len(dataindex)))
h = sigmoid(np.dot(datamat[randindex], weights.transpose()))
error = h - inputlable[randindex]
weights = weights - alpha * error * datamat[randindex]
del (dataindex[randindex])
return weights.transpose()
if __name__ == "__main__":
data, label = loaddata()
weights1 = randomgradacent(data, label, 2000)
weights2 = gradacent(data, label)
h = sigmoid(np.dot(data, weights2))
length = len(h)
error = 0
for i in range(length):
if h[i][0] > 0.5:
if label[i] != 1:
error += 1
else:
if label[i] != 0:
error += 1
print(error / length)
总结
这次可能文字有点少,都是数学推导,这也是我头一次完整的能够把一个模型的数学推导写出来,所以更多的是总结了自己在数学方面的一些问题,下一篇应该是SVM吧:star2:
Comments | 2 条评论
文章写的不错,加油~
谢谢分享,日常打卡~ 滴滴~