目录
前言:
Logistic回归是一种十分常见的分类模型,是的严格来说这是一个分类模型,之所以叫做回归也是由于历史原因。不同于线性回归中对于参数的推导,我们在这里运用的方式不再是最小二乘法,而是极大似然估计。
Logistic回归简介
逻辑斯谛回归(logistic regression)是统计学习中的经典分类方法,属于对数线性模型,所以也被称为对数几率回归。这里要注意,虽然带有回归的字眼,但是该模型是一种分类算法,逻辑斯谛回归是一种线性分类器,针对的是线性可分问题。利用logistic回归进行分类的主要思想是:根据现有的数据对分类边界线建立回归公式,以此进行分类。这里的“回归”一词源于最佳拟合,表示要找到最佳拟合参数集,因此,logistic训练分类器时的做法就是寻找最佳拟合参数,使用的是最优化方法
前期引入
线性模型与回归
线性模型一般形式:
其中x=(x1, x2, ..., xd)是由d维属性描述的样本,其中 xi 是 x 在第 i 个属性上的取值。
向量形式可记为:
f ( x )= wT x + b
其中w=(w1, w2, ..., wd)为待求解系数
我们可以根据样本来拟出一条直线,如下:
给定数据集 D={(x1, y1), (x2, y2), ..., (xm, ym)}
其中xi=(xi1, xi2, ..., xid), yi ∈R
线性回归(linear regression)目的:

最小二乘与参数求解
线性回归目标:
参数/模型估计:最小二乘法(least square method)
考虑xi是一维数据,设其回归值𝑓(𝑥𝑖)f(x_i)与实际观察 𝑦𝑖y_i 之间存在的误差 𝑒𝑖〖 e〗_i,则学习的目标为:
最小化均方误差:
分别对w和b求导,可得:
•得到解析/闭合(closed-form)解:
回归的基本思想
根据训练数据和分类边界线方程(方程参数未知),得到最佳拟合参数集,从而实现数据的分类。通常,Logistic回归适用于二值型输出分类,即二分类,也就是分类结果只有两种情况:是与否,发生与不发生等。
Sigmod函数
既然,Logistic回归的输出只有两种情况,那么我们有必要引入一种函数,该函数只有两种输出,0或者1。有人可能会想到单位阶跃函数,没错,确实可以,但是考虑到单位阶跃函数是分段函数,其在x=0处的跳变不方便用代码处理。故此,我们介绍另外一种函数——Sigmod函数。其实,从数学的角度上讲,这也是一种阶跃函数。
Sigmoid函数也叫Logistic函数,取值范围为(0,1),它可以将一个实数映射到(0,1)的区间,可以用来做二分类。
其基本图形如下:
当x=0时,Sigmod(0)的值为0.5。为了实现分类器,我们将每个样本的每个特征值乘以相应的回归系数,然后求和,并带入Sigmod函数。当结果大于0.5时,该样本被归为1类;当结果小于0.5时,该样本归为0类。这样我们就实现了Logistic的二分类。所以,Logistic分类,也是一种概率估计,即样本有多大的概率被划分为某一类。
Logistic回归
分类问题

g(∙)称为联系函数(link function),该函数一般为单调可微函数。
•对数线性回归是 g(∙)=ln(∙) 时广义/多维线性模型的特例。

寻找函数将分类标记与线性回归模型输出联系起来。
单位阶跃函数:
所以:逻辑回归是拟合“y的sigmoid函数”


极大似然法




记:
可简写为:
梯度下降
数据分类
给定数据样本:
分类:
代码实现
数据准备
将数据放在testSet.txt里面:
数据集内容如下:
以上只展示一部分数据。
代码实现:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from numpy import *
import matplotlib.pyplot as plt
#从文件中加载数据:特征X,标签label
def loadDataSet():
dataMatrix=[]
dataLabel=[]
#这里给出了python 中读取文件的简便方式
f=open('testSet.txt')
for line in f.readlines():
#print(line)
lineList=line.strip().split()
dataMatrix.append([1,float(lineList[0]),float(lineList[1])])
dataLabel.append(int(lineList[2]))
#for i in range(len(dataMatrix)):
# print(dataMatrix[i])
#print(dataLabel)
#print(mat(dataLabel).transpose())
matLabel=mat(dataLabel).transpose()
return dataMatrix,matLabel
#logistic回归使用了sigmoid函数
def sigmoid(inX):
return 1/(1+exp(-inX))
#函数中涉及如何将list转化成矩阵的操作:mat()
#同时还含有矩阵的转置操作:transpose()
#还有list和array的shape函数
#在处理矩阵乘法时,要注意的便是维数是否对应
#graAscent函数实现了梯度上升法,隐含了复杂的数学推理
#梯度上升算法,每次参数迭代时都需要遍历整个数据集
def graAscent(dataMatrix,matLabel):
m,n=shape(dataMatrix)
matMatrix=mat(dataMatrix)
w=ones((n,1))
alpha=0.001
num=500
for i in range(num):
error=sigmoid(matMatrix*w)-matLabel
w=w-alpha*matMatrix.transpose()*error
return w
#随机梯度上升算法的实现,对于数据量较多的情况下计算量小,但分类效果差
#每次参数迭代时通过一个数据进行运算
def stocGraAscent(dataMatrix,matLabel):
m,n=shape(dataMatrix)
matMatrix=mat(dataMatrix)
w=ones((n,1))
alpha=0.001
num=20 #这里的这个迭代次数对于分类效果影响很大,很小时分类效果很差
for i in range(num):
for j in range(m):
error=sigmoid(matMatrix[j]*w)-matLabel[j]
w=w-alpha*matMatrix[j].transpose()*error
return w
def stocGraAscent1(dataMatrix,matLabel):
m,n=shape(dataMatrix)
matMatrix=mat(dataMatrix)
w=ones((n,1))
num=200 #这里的这个迭代次数对于分类效果影响很大,很小时分类效果很差
setIndex=set([])
for i in range(num):
for j in range(m):
alpha=4/(1+i+j)+0.01
dataIndex=random.randint(0,100)
while dataIndex in setIndex:
setIndex.add(dataIndex)
dataIndex=random.randint(0,100)
error=sigmoid(matMatrix[dataIndex]*w)-matLabel[dataIndex]
w=w-alpha*matMatrix[dataIndex].transpose()*error
return w
#绘制图像
def draw(weight):
x0List=[];y0List=[];
x1List=[];y1List=[];
f=open('testSet.txt','r')
for line in f.readlines():
lineList=line.strip().split()
if lineList[2]=='0':
x0List.append(float(lineList[0]))
y0List.append(float(lineList[1]))
else:
x1List.append(float(lineList[0]))
y1List.append(float(lineList[1]))
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(x0List,y0List,s=10,c='red')
ax.scatter(x1List,y1List,s=10,c='green')
xList=[];yList=[]
x=arange(-3,3,0.1)
for i in arange(len(x)):
xList.append(x[i])
y=(-weight[0]-weight[1]*x)/weight[2]
for j in arange(y.shape[1]):
yList.append(y[0,j])
ax.plot(xList,yList)
plt.xlabel('x1');plt.ylabel('x2')
plt.show()
if __name__ == '__main__':
dataMatrix,matLabel=loadDataSet()
#weight=graAscent(dataMatrix,matLabel)
weight=stocGraAscent1(dataMatrix,matLabel)
print(weight)
draw(weight)
运行结果:
总结
Logistic回归是一种常用的分类算法,适用于二分类问题。通过对数据进行训练,可以得到一个分类边界,将数据分为两个类别。
在这个实验中,我们使用了两种方法来实现Logistic回归:梯度上升算法和随机梯度上升算法。梯度上升算法每次迭代都需要遍历整个数据集,计算量较大;而随机梯度上升算法每次迭代只需要随机选取一个样本进行计算,计算量较小。同时,随机梯度上升算法还引入了学习率的概念,使得每次迭代的步长不固定,可以更好地适应数据。
在实验过程中,我们加载了一个数据集,并使用训练数据来训练模型。训练过程中,我们根据模型的预测结果和实际标签之间的误差来更新模型参数,使得模型的预测结果更加准确。最终,得到了一个分类边界,并使用绘图函数将分类结果可视化。
总结起来,Logistic回归是一种简单而有效的分类算法,在处理二分类问题时具有较好的效果。通过实验,我们可以了解到不同的算法对分类结果的影响,并选择合适的方法来解决实际问题。
以下为Logistic回归的优缺点:
优点:
- 实现简单:Logistic回归是一个相对简单的分类算法,易于理解和实现。
- 计算代价低:相比其他复杂的分类算法,Logistic回归的计算代价较低,训练速度较快。
- 输出结果易于理解:Logistic回归输出的结果可以被解释为概率,而不仅仅是类别标签,这使得结果更易于理解。
缺点:
- 只能处理二分类问题:Logistic回归只能解决二分类问题,对于多分类问题需要进行改进或者组合其他算法。
- 对特征工程敏感:Logistic回归对输入特征的线性关系假设比较严格,如果特征之间的关系不是线性的,可能会导致分类效果不佳。
- 容易欠拟合:当特征之间的关系较为复杂时,Logistic回归可能会出现欠拟合的情况,分类效果不佳。