1 Logistic回归总结:
Logistic回归: Logistic回归可以用来回归,也可以用来分类(主要二分类);通过sigmoid函数将一组特征的结果映射到0-1之间,通过与结果的误差来更新权值进行权值的更新。最后的使得结果接近真实值,其中的损失函数和更新权值的方法(梯度下降,随机梯度下降等)需要重点掌握。
2 Logistic回归的应用场景和优缺点
应用场景:1)预测是否发生、发生的概率(流失、客户响应等预测);2)影响因素、危险因素分析(找出影响结果的主要因素); 3)判别、分类如判断某人属于某病或属于某种情况的概率有多大等
优点:1)预测结果是界于0和1之间的概率;2)可以适用于连续性和类别性自变量;3)容易使用和解释;
缺点:1)对模型中自变量多重共线性较为敏感,需要利用因子分析或者变量聚类分析等手段来选择代表性的自变量,以减少候选变量之间的相关性;2)预测结果呈“S”型,导致很多区间的变量变化对目标概率的影响没有区分度,无法确定阀值等
3 算法过程
首先找到一个函数,进行拟合,然后通过构造损失函数,通过梯度迭代的方法逐渐的改变权重,来缩小误差,最后取得最小的误差值。
4 具体实例
4.1 对构建的简单数据进行分类
from numpy import *
'''
#读取文本内容的函数
'''
def loadDataSet():
dataMat = [] #创建数据列表
labelMat = [] #创建标签列表
fr = open('C:/Users/Administrator/Desktop/Ch05/testSet.txt') #打开文件
for line in fr.readlines(): #逐行读取
lineArr = line.strip().split() #将一行数据按照空格切分
#在第一列添加1(为后面回归*b做铺垫)
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
#读取标签数据
labelMat.append(int(lineArr[2]))
return dataMat,labelMat #返回数据和标签
'''
#sigmoid函数
# inx : 输入数据
'''
def sigmoid(inX):
return 1.0/(1+exp(-inX))
'''
#梯段上升函数
# dataMatIn : 输入数据数组
# classLabels : 输入数据标签数组
'''
def gradAscent(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn) #输入数据转换为矩阵
labelMat = mat(classLabels).transpose() #得到矩阵的转置矩阵
m,n = shape(dataMatrix) #数组矩阵的尺寸
alpha = 0.001 #移动步长(学习速率)控制更新的幅度
maxCycles = 500 #迭代次数
weights = ones((n,1)) #构建b和权重w的系数矩阵
for k in range(maxCycles): #矩阵运算次数k
#计算sigmoid的函数值,h是一个100x1的矩阵(一个样本一个值,100个样本)
h = sigmoid(dataMatrix*weights)
#矢量作差(用于回归最佳系数计算的迭代)
error = (labelMat - h)
#矩阵迭代,由逻辑斯特中梯度上升算法进行更新权重
weights = weights + alpha * dataMatrix.transpose()* error
return weights #返回权重
'''
#画出原始数据集和拟合曲线函数
# weights : 回归系数矩阵
'''
def plotBestFit(weights):
import matplotlib.pyplot as plt #导入做图的库
dataMat,labelMat=loadDataSet() #读取数据和数据对应的类别标签
dataArr = array(dataMat) #将dataMat列表数据转换成矩阵
n = shape(dataArr)[0] #得到矩阵dataArr的行数
#初始化列表,将属于类型1的两类数据作为可视化坐标上的x和y存在xcord1和ycord1
xcord1 = []; ycord1 = []
xcord2 = []; ycord2 = []
for i in range(n): #读取类型标签集的每一个标签
if int(labelMat[i])== 1: #判断数据标签类型
#标签为1,将每个样本对应的两个数据存放在xcord1和ycord1里
xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
else:
#标签为0,将每个样本对应的两个数据存放在xcord2和ycord2里
xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
#建立可视化图形
fig = plt.figure()
#建立一个窗口
ax = fig.add_subplot(111)
#将标签为1的每个样本画在可视化图像上
ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
#将标签为0的每个样本画在可视化图形上
ax.scatter(xcord2, ycord2, s=30, c='green')
#以0.1为步长,从-3.0到3.0显示x的刻度
x = arange(-3.0, 3.0, 0.1)
#该处设置了sigmoid函数为0,0是两个分类(类别1和类别0的分界处)
y = (-weights[0]-weights[1]*x)/weights[2]
ax.plot(x, y) #将决策边界线画在可视化图像上
plt.xlabel('X1'); plt.ylabel('X2'); #标注横轴为X1,纵轴为X2
plt.show() #可视化图形显示
'''
#随机梯度上升算法函数
# dataMatIn : 输入数据数组
# classLabels : 输入数据标签数组
'''
def stocGradAscent0(dataMatrix, classLabels):
m,n = shape(dataMatrix)
#移动步长(学习速率)控制更新的幅度
alpha = 0.01
#构建b和权重w的系数矩阵
weights = ones(n)
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
#随机选择部分数据与标签的错误差距
error = classLabels[i] - h
#矩阵迭代,由逻辑斯特中梯度上升算法进行更新权重
weights = weights + alpha * error * dataMatrix[i]
return weights #返回权重
'''
#改进的随机梯度上升算法函数
# dataMatIn : 输入数据数组
# classLabels : 输入数据标签数组
# numIter :迭代次数
'''
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = shape(dataMatrix) #返回dataMatrix的大小
weights = ones(n) #参数初始化
for j in range(numIter):
dataIndex = range(m)
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001 #降低alpha的大小,每次减小1/(j+i)
randIndex = int(random.uniform(0,len(dataIndex))) #随机选取样本
#选择随机选取的一个样本,计算h
h = sigmoid(sum(dataMatrix[randIndex]*weights))
#计算误差
error = classLabels[randIndex] - h
#更新回归系数
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex]) #删除已经使用的样本
return weights #返回权重
以上所有函数可以在自己的jupyter中实现或者pycharm中调试,从其运行过程中加深对算法的认识。其中有梯度上升算法,随机梯度上升算法及其的改进算法。
5 权值更新的方法
梯度上升和梯度下降类似,在此比较梯度下降方法的不同之处
梯度下降:全量梯度下降就是我上面的推导,要留意,在梯度下降中,对于θθ的更新,所有的样本都有贡献,也就是参与调整θ.其计算得到的是一个标准梯度。因而理论上来说一次更新的幅度是比较大的。如果样本不多的情况下,当然是这样收敛的速度会更快啦。
随机梯度下降:可以看到多了随机两个字,随机也就是说我用样本中的一个例子来近似我所有的样本,来调整θθ,因而随机梯度下降是会带来一定的问题,因为计算得到的并不是准确的一个梯度,容易陷入到局部最优解中。
批量梯度下降:其实批量的梯度下降就是一种折中的方法,他用了一些小样本来近似全部的,其本质就是我1个指不定不太准,那我用个30个50个样本那比随机的要准不少了吧,而且批量的话还是非常可以反映样本的一个分布情况的。