逻辑回归(Logistic Regression),是一种分类算法,该算法将样本的特征和样本发生的概率联系起来,通过发生的概率将数据分成两类。
(一)数学原理
逻辑回归是计算一种特征发生的概率,如果概率p大于0.5,就分类为1,小于0.5分类为0,因此逻辑回归的过程是一个回归算法,而经过最终处理后可用于分类,并且由原理可知,逻辑回归只能实现二分类
1.1概率求法
由于概率值限于[0,1],因此用于计算概率的函数值域应介于0~1之间,并且概率函数是一个一元的函数,每次接收的是一个数,返回的是概率值,因此,这部分求解的思维转变为先对样本进行线型回归或多项式回归,继而求出每个样本回归预测值,回归值得范围是[-inf,+inf],之后将回归结果送入概率密度函数,求出概率值,最后判断概率值与0.5的大小关系,即可判得出分类结果。
这里的表示概率的函数为Sigmoid函数,表达式为如上,绘制sigmoid的图像,如下图所示,是一个介于0和1之间的曲线,可以发现,当t小于0时,函数值小于0.5,t大于0时,函数值大于0.5,因此,用于判断分类结果的标准可以理解为回归值与0的大小关系。当预测结果大于0,分类为1,小于0则分类为零
逻辑回归的算法如下所示:
1.2 损失函数&参数求解
回归算法的损失函数是通过预测值与实际值的误差来评判的,而分类算法只有两个值,欲求逻辑回归的损失函数,需要根据数学原理来推导
其函数图像如下图:当样本真值为1时,概率越小,被判为0的可能性就越大,那么损失函数值越大,反之同理。
那么,对于m各样本,所有的损失之和见下式,其中Xb是在样本之前添加了一列全为1的特征,可见,损失函数是一个关于参数θ的函数。逻辑回归的目的同样是使得损失函数值最小,由于该函数并不能直接通过使导数值为零,而获得一个关于θ的表达式,而且,损失函数是一个凸函数,没有局部最优解,只存在一个全局最优解。因此,可以用梯度下降法来求得使损失函数最小的一组θ值
1.3损失函数的梯度
求损失函数的关于每一个参数的偏导数,只需要先求出其中一个,其他类推。这里为了简洁化,首先求Sigmoid函数的导数
(二)算法实现
输入:样本,初始参数θ
输出:参数θ
数学方法:梯度下降法
辅助函数:目标函数、目标函数导数、激活函数sigmoid
2.1基于线性回归
import numpy as np
class LogisticRegression:
def __init__(self):
self.coef_=None
self.intercept_=None
self._theta=None
def sigmoid(self,t):
return 1/(1+np.exp(-t))
def fit(self,x,y,eta,epsilon):
def J(x_b,y,theta):
t=x_b.dot(theta)
p=self.sigmoid(t)
try:
return np.sum(y.dot(np.log(p))+(1-y).dot(np.log(1-p)))/(-len(y))
except:
return float('inf')
def dJ(x_b,y,theta):
p=self.sigmoid(x_b.dot(theta))
return x_b.T.dot(p-y)/len(y)
def gradient_descent(initial_theta,x_b,y,n_iters=1e4):
theta=initial_theta
i_iter=0
while i_iter<n_iters:
J1=J(x_b,y,theta)
gradient=dJ(x_b,y,theta)
theta=theta-eta*gradient
J2=J(x_b,y,theta)
if np.absolute(J1-J2)<epsilon:
break
i_iter+=1
return theta
x_b=np.hstack((np.ones((len(x),1)),x))
initial_theta=np.random.normal(0,1,size=x_b.shape[1])
self._theta=gradient_descent(initial_theta,x_b,y)
self.coef_=self._theta[1:x_b.shape[1]]
self.intercept_=self._theta[0]
def predict_proba(self,x_test):
x_b=np.hstack((np.ones((len(x_test),1)),x_test))
t=x_b.dot(self._theta)
p=self.sigmoid(t)
return p
def predict(self,x_test):
return np.array(self.predict_proba(x_test)>=0.5,dtype='int')
def __repr__():
return 'LogisticRegression()'
2.2基于多项式
逻辑回归的本质是在特征平面中确定一个决策边界,从而将样本分成两类,之前基于线性回归的逻辑回归的本质就是在特征平面中确定一条直线,来分割对应的两种分类。依据数学原理,它的决策边界就是直线方程θTXb=0,但仅仅基于线性回归的逻辑回归只能解决线性可分问题,无法解决线性不可分问题。基于以上分析,逻辑回归在有些情况下就需要添加多项式特征。
这里,数据首先经过添加多项式,之后标准化处理,最后进行逻辑回归,需要依次经过三个步骤,因此,采用Pipeline类。
from sklearn.pipeling import Pipeline
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.linear_model import LogisticRegression
def PolynomialLogisticRegression(degree):
return Pipeline([
('poly',PolynomialFeatures(degree=degree)),
('std',StandardScaler()),
('log',LogisticRegression())
])
poly_log_reg=PolynomialLogisticRegression(degree)
poly_log_reg.fit(x_train,y_train)
poly_log_reg.predict_prabo(x_test)
poly_log)reg.predict(x_test)
其中,LogisticRegressio不一定是sklearn库中的类,也可以是自己定义的,即便是自己定义的,只要遵循sklearn的标准,有构造函数、fit、predict、等,就可以与其他sklearn中的类衔接
2.3 sklearn中的逻辑回归正则化
逻辑回归中添加多项式项可以生成不规则的决策边界,实现对非线性数据的分类。多项式项的引入会使得模型复杂,有可能过拟合,用于解决过拟合的一个常用方法是为模型添加正则项。
逻辑回归中添加正则项的方式是:C·J(θ)+L1或者C·J(θ)+L2,通过控制C的大小来改变正则项的重要程度,sklearn中的逻辑回归和SVM都使用这种正则化方法,可以保证正则项前面的系数不为0
sklearn中的逻辑回归,默认参数:正则项是penalty=‘L2’,C=1.0,因此在实例化时,可以通过传入参数penalty和C来调节过拟合问题
sklearn中实例LogisticRegression并经过训练之后,默认情况下,返回以下内容。
LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, max_iter=100, multi_class=‘ovr’, n_jobs=1,
penalty=‘l2’, random_state=None, solver=‘liblinear’, tol=0.0001,
verbose=0, warm_start=False)
(三)用逻辑回归实现多分类问题——OvR(或者OvA)与OvO
3.1OvR(One vs Rest)
OvR(One vs Rest)——一对剩余的所有,如下图中,有四类,由于逻辑回归只能处理二分类问题,因此下图中问题不能直接使用逻辑回归,OvR的思路就是,选取其中的某一个为一类,剩余的三个类别合为一类称为其他类别,这样四分类问题转换为二分类问题,依据逻辑回归的原理,当一个新的样本出现,首先计算属于红色的样本点的概率和不属于红色的概率,同样的方法计算新样本属于其他另外三种颜色的概率,最终,概率最高的就是新的样本的类别。
3.2OvO(One vs One)
OvO(One vs One)——一对一进行比较:每次挑两个类别,进行二分类任务,那么如果有n类,就需要进行C2n次二分类,同样每种分类中,都判断概率,最终六个分类中概率最大的就是所求。
由2.3中默认情况下,逻辑回归返回的内容可知, 默认情况下multi_class=‘ovr’,即采用第一种方式实现多分类, 若要使用OVO,则需要在实例化时传入参数multi_class=‘multinomial’,solver=‘newton-cg’
3.3sklearn中对应的库
from sklearn.multiclass import OneVsRestClassifier
ovr=OneVsRestClassifier(log_reg) #这里的log_reg是一个实例化的二分类器,是逻辑回归类实例化的对象
ovr.fit(x_train,y_train)
ovr.score(x_test,y_test)
#####################################################################################################
from sklearn.multiclass import OneVsOneClassifier
ovo=OneVsOneClassifier(log_reg)
ovo.fit(x_train,y_train)