逻辑回归
本系列重点在浅显易懂,快速上手。不进行过多的理论讲解:也就是不去深究what,而是关注how。全文围绕以下三个问题展开:
1)长什么样?
2)解决什么问题?
3)怎么实现?
3.1)从数学讲,原理
3.2)从代码上讲,如何掉包实现
长什么样
上节讲了线性回归,解决回归问题的方式。回归问题的y值是连续的,例如:房价。线性回归模型的输出是连续的,值域范围是(-∞,+∞)可以解决回归问题不难理解,但如何用线性回归解决分类问题呢?
因为分类问题(例如预测明天是晴天还是下雨,1表示晴天,0表示下雨)的值域是0或者1。或者说分类问题的值域应该是[0,1]之间的值,表示事情发生的概率,例如0.8,表示明天晴天的概率是0.8,但仍然对接不上线性回归模型(-∞,+∞)的值域范围。
这里就需要引入几率的概念,即:odds=\frac{p}{1-p},odds的取值范围是[0,+∞],再取对数log,即:log(odds)=log(\frac{p}{1-p}),取值范围就是(-∞,+∞)了。所以用线性回归解决分类问题,实际上是,去拟合log(odds)。
即:
$$
θ^Tx=log(odds)=log(\frac{p}{1-p})\\ p=\frac{1}{1+e^{-θ^Tx}},这就是大名鼎鼎的sigmoid函数了
$$
所以逻辑回归,实际上就是再线性回归的基础上,经过一层sigmoid函数,就可以解决分类问题了。
解决什么问题
先看一组数据(一组sklearn中公开的数据集,鸢尾花的种类预测,共有4个特征,最后一列y是花的种类,逻辑回归只能解决二分类问题,所以这里只取y=0或者1两种类型,下面展示了5条数据,实际数据有100条):
采用逻辑建模,最终的目的就是为了找到一组θ_1,θ_2,θ_3,θ_4,θ_0(除了4个系数,还包含一个常数项θ_0),使得下式成立。
$$
\frac{1}{1+e^{-(θ_1*x1+θ_2*x2+θ_3*x3+θ_4*x4+θ_0)}} =y
$$
最后就通过下面的式子,来预测鸢尾花的类型。
怎么实现
数学理论
设我们最终得到的模型如下
$$
h_θ(x)=\frac{1}{1+e^{-θ^Tx}}
$$
h_θ(x)实际上预测的是,取1的概率,即:
:
取0的概率,即
建立似然函数如下:
很明显这应该求似然函数的最大值,
转换为对数似然函数为
求导,
转换为矩阵形式,
$$
\frac{\partial l(θ)}{\partial θ} = X^T(Y-\frac{1}{1+e^{-Xθ}})
$$
既然要求l(θ)的最大值,就是梯度提升的方式,即:
$$
θ = θ+α*\frac{1}{m}*\frac{\partial l(θ)}{\partial θ} \\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ = θ+α*\frac{1}{m}*X^T(Y-\frac{1}{1+e^{-Xθ}})
$$
逻辑回归的损失函数为交叉熵损失函数(也叫对数损失函数):
手写代码实现
#_*_coding:utf-8_*_
import numpy as np
import pandas as pd
from sklearn import datasets
from tqdm import tqdm, trange
import matplotlib.pyplot as plt
class Logistic():
def __init__(self,X,Y,theta):
self.theta = theta
self.X = X
self.Y = Y
def H(self):
result = 1/(1+np.exp(-1*np.dot(self.X,self.theta)))
return result
def R(self):
predict = self.H()
result = np.dot(self.X.T,(self.Y-predict))
return result
def L(self):
predict = self.H()
predict[self.Y==0] = 1-predict[self.Y==0]
result = -1*np.sum(np.log(predict))
return result
def train(self,epoch,learn_rate):
for i in range(epoch):
loss = self.L()
self.theta = self.theta + learn_rate*self.R()
print(loss)
print(self.H())
if __name__ == '__main__':
data = datasets.load_iris()
X = data.data[data.target<2]
Y = data.target[data.target<2].reshape(-1,1)
theta = np.random.random((X.shape[1],1))
LR = Logistic(X, Y,theta)
LR.train(epoch = 1000000,learn_rate=0.0001)
print('Done')
sklearn调包实现
这里直接讲解,如何调用sklearn实现。
from sklearn.linear_model import LogisticRegression #sklearn中,线性回归模型在linear_model模块中
# 调取sklearn中自带的数据集
from sklearn.datasets import load_iris #调用上文一开始提到大波士顿房价数据集
X, y = load_boston(return_X_y=True) #获取X,y数据
ndarray = np.c_[X,y]
X = ndarray[np.where(ndarray[:,-1:]<2)[0]] #逻辑回归做2分类,只筛选y值为0和1的样本
LR = LogisticRegression() #初始化一个线性回归模型
LR.fit(X,y) #fit函数用于训练
LR.predict(X) #predict函数用于预测
LR.coef_ #coef_用于返回θ的值
LR.intercept_ #intercept_用于返回常数项的值(截距)
更多内容可以参考sklearn的官方文档
sklearn.linear_model.LogisticRegression — scikit-learn 1.3.0 documentation