机器学习实战:逻辑回归+梯度下降

Rowena ·
更新时间:2024-11-11
· 752 次阅读

使用梯度下降的方法进行逻辑回归实战:

问题说明:
这里将建立一个逻辑回归模型来预测一个学生是否被大学录取。
假设你是一个大学的管理员,你想根据两次考试的结果来决定每个申请人的录取机会,你有以前的申请人的历史数据。可以用历史数据作为逻辑回归的训练集。对于每一个样本,有两次考试的申请人的成绩和录取决定。建立一个分类模型,根据考试成绩估计入学概率。

数据链接:
链接:https://pan.baidu.com/s/1-pjwe1ogk30WpzN4Qg1NZA 密码:wqmt

完整代码实现如下:

import numpy as np import pandas as pd import matplotlib.pyplot as plt pdData = pd.read_csv('/Users/hxx/Downloads/LogiReg_data.txt', header=None, names=['Exam1', 'Exam2', 'Admitted'], engine='python') #header: 指定第几行作为列名(忽略注解行),如果没有指定列名,默认header=0; 如果指定了列名header=None #names 指定列名,如果文件中不包含header的行,应该显性表示header=None。这边列名为'Exam1', 'Exam2', 'Admitted'三列 print(pdData.head())#head()函数默认读取前五行 print(pdData.shape)#数据文件100行3列 positive = pdData[pdData['Admitted']==1] negative = pdData[pdData['Admitted']==0] plt.figure(figsize=(10,5))#设置画布 plt.scatter(positive['Exam1'], positive['Exam2'], c='b', marker='o', label='Admitted')#绘制散点图positive的点,Exam1和Exam2组成一个点 plt.scatter(negative['Exam1'], negative['Exam2'], c='r', marker='x', label='Not Admitted')#绘制散点图negative的点 plt.legend()# 添加图例(也就是图中右上角positive和negative的解释) plt.xlabel('Exam1 Score')#添加x轴标签 plt.ylabel('Exam2 Score')#添加y轴标签 plt.show() #定义sigmoid函数 def sigmoid(z): return 1/(1+np.exp(-z)) nums = np.arange(-10,10,step=1)#随机取-10到10之间数值步长为1 plt.figure(figsize=(12,4))#设置画布 plt.plot(nums,sigmoid(nums),c='r')#sigmoid函数画图展示,nums表示x,sigmoid(nums)表示的y,x和y确定一点组成sigmoid函数图像 plt.show() #定义模型h(x) def model(X,theta): return sigmoid(np.dot(X,theta.T))#将theta转置与x相乘,在代入sigmoid函数中得到模型。X是100*3列,theta是一行三列 #取数据 pdData.insert(0,'ones',1) #给数据添加一列,列名为ones,在第0列添加,数值为1,也就相当于x_0的系数theta_0 orig_data = pdData .as_matrix() # 将数据转变成矩阵形式 cols = orig_data .shape[1]#shape[0]就是读取矩阵第一维度的长度,相当于行数;shape[1]就是读取矩阵第二维度的长度,相当于列数,shape[1]=4 X = orig_data[:,0:cols-1]#逗号前冒号表示所有值,0:cols-1表示取第0列到(clos-1)列不包括cols-1这一列 y = orig_data[:,cols-1:cols] theta = np.zeros([1,3])#这边设置theta值均为0,一行三列和x的一行三列相对应 print(X) print(y) print(theta) #定义损失函数 #这边就是逻辑回归中的损失函数,逻辑回归详情可以参考:https://blog.csdn.net/hxx123520/article/details/104313032第四部分详细说明 def cost(X,y,theta):#对应于J(theta) left = np.multiply(-y,np.log(model(X,theta)))#np.multiply对应位置相乘 right = np.multiply(1-y,np.log(1-model(X,theta))) return np.sum(left-right)/(len(X)) print(cost(X,y,theta)) #根据梯度计算公式计算梯度 #也就是损失函数对theta求偏导,得到的就是梯度 def gradient(X,y,theta): grad = np.zeros(theta.shape) # 定义初始化梯度,一行三列 #print(grad.shape) error = (model(X, theta) - y).ravel()# 一行一百列。error=(预测y-真实值y) #print(error) # print(len(theta .ravel()))#3 for j in range(len(theta.ravel())): term = np.multiply(error, X[:, j])#x[:,j] 取第j列的所有x样本 grad[0, j] = np.sum(term) / len(X)#这边的grad就是一行三列。grad[0,0]表示第0行第0列,for循环不断更新j,最终就是[0,2]表示0行2列 #print(grad) return grad #numpy中的ravel()、flatten()、squeeze()都有将多维数组转换为一维数组的功能,区别: #ravel():如果没有必要,不会产生源数据的副本。这边的error就是通过ravel函数将一百行一列拉成一行100列 #flatten():返回源数据的副本 #squeeze():只能对维数为1的维度降维 #三种梯度下降方法与三种停止策略 #三种停止策略 STOP_ITER=0 #根据指定的迭代次数来停止,更新一次参数相当于一次迭代 STOP_COST=1 #根据损失,每次迭代看一下迭代之前和之后的目标函数(损失值)的变化,没啥变化的话,可以停止 STOP_GRAD=2 #根据梯度,梯度变化贼小贼小 #设定三种不同的停止策略 def stopCriterion(type,value,threshold): if type == STOP_ITER: return value > threshold #threshold指的是指定的迭代次数 elif type ==STOP_COST: return abs(value[-1]-value[-2]) < threshold#threshold指的损失函数的阈值,如果小于这个值就停止 elif type == STOP_GRAD: return np.linalg.norm(value) = n : k=0 X,y=shuffleData(data) theta=theta-alpha * grad#theta是一行三列,减去alpha*grad的一行三列,也就是更新后的theta costs.append(cost(X,y,theta))#将损失值添加到costs中。append() 方法向列表的尾部添加一个新的元素。 i+=1; if stoptype==STOP_ITER: value=i if stoptype==STOP_COST:value=costs if stoptype==STOP_GRAD:value=grad if stopCriterion(stoptype,value,thresh):break return theta,i-1,costs,grad,time.time()-init_time def runExpe(data,theta,batchsize,stoptype,thresh,alpha): theta, iter, costs, grad, dur = descent(data,theta,batchsize,stoptype,thresh,alpha) if (data[:,1]>2).sum()>1: name="Original" else: name="Scaled" name=name + " data - learning rate: {} -".format(alpha) if batchsize==n: strDescType = "Gradient" #batchsize等于n是全局随机梯度下降 elif batchsize==1: strDescType = "Stochastic" #batchsize等于1是随机梯度下降 else: strDescType = "Mini-batch({})".format(batchsize)#小批量梯度下降 name = name + strDescType + " descent - stop :" if stoptype==STOP_ITER: strstop = "{} iterations".format(thresh) elif stoptype==STOP_COST: strstop = "cost change < {}".format(thresh) else: strstop = "gradient norm =0.5 else 0 for x in model(X,theta)]#设定阈值为0.5,大于0.5就可以入学 scaled_X = scaled_data[:,:3] y = scaled_data[:,3] prediction = predict(scaled_X,theta) correct = [1 if ((a==1 and b==1) or (a==0 and b==0)) else 0 for (a,b) in zip(prediction,y)]#a对应的prediction值,b对应的真实值y accuracy = (sum(map(int,correct)) % len(correct))#map() 会根据提供的函数对指定序列做映射。这边将correct映射为整数型在进行求和 print("accuracy {0}%".format(accuracy)) 2.接下来详细的介绍一下不同的停止策略在上面代码中已经给出 2.1 批量梯度下降为例(batchsize=n=100) 停止条件为迭代次数5000 runExpe(orig_data, theta, n, STOP_ITER, thresh=5000, alpha=0.000001)

返回

*Original data - learning rate: 1e-06 -Gradient descent - stop :5000 iterations Theta: [[-0.00027127 0.00705232 0.00376711]] - Iter: 5000 - Last cost: 0.63 - Duration: 0.95s

在这里插入图片描述看似损失值已经稳定在最低点0.63

停止条件为损失值

设定阈值为0.000001,需要迭代110000次左右

runExpe(orig_data, theta, n, STOP_COST, thresh=0.000001, alpha=0.001)

返回

*Original data - learning rate: 0.001 -Gradient descent - stop :cost change < 1e-06 Theta: [[-5.13364014 0.04771429 0.04072397]] - Iter: 109901 - Last cost: 0.38 - Duration: 20.22s

在这里插入图片描述损失值最低为0.38,似乎还可以进一步收敛

停止条件为梯度大小

设定阈值0.05,需要迭代40000次左右

runExpe(orig_data, theta, n, STOP_GRAD, thresh=0.05, alpha=0.001)

返回

*Original data - learning rate: 0.001 -Gradient descent - stop :gradient norm < 0.05 Theta: [[-2.37033409 0.02721692 0.01899456]] - Iter: 40045 - Last cost: 0.49 - Duration: 7.67s

在这里插入图片描述损失值最小为0.49,似乎还可以进一步收敛
综上,基于批量梯度下降方法,上述三种停止条件得到的损失函数值为0.63、0.38和0.49,迭代次数分别为5000次、110000次和40000次,迭代次数越多,损失值越小

3.对比不同的梯度下降方法

停止策略为迭代次数

3.1 随机梯度下降 runExpe(orig_data, theta, 1, STOP_ITER, thresh=5000, alpha=0.001)

返回

*Original data - learning rate: 0.001 -Stochastic descent - stop :5000 iterations Theta: [[-0.38740891 0.09055956 -0.06431339]] - Iter: 5000 - Last cost: 0.91 - Duration: 0.31s

在这里插入图片描述波动非常大,迭代过程不稳定,这也是随机梯度下降的主要缺点
尝试降低学习率为0.000002,增加迭代次数为15000

runExpe(orig_data, theta, 1, STOP_ITER, thresh=15000, alpha=0.000002)

返回

*Original data - learning rate: 2e-06 -Stochastic descent - stop :15000 iterations Theta: [[-0.00202428 0.00981444 0.00076997]] - Iter: 15000 - Last cost: 0.63 - Duration: 0.93s

在这里插入图片描述效果要好一些,损失值似乎稳定在0.63,根据上面的结果可知,0.63不算是一个特别合理的值

3.2 小批量梯度下降 #取样本为16 runExpe(orig_data, theta, 16, STOP_ITER, thresh=15000, alpha=0.001)

返回

*Original data - learning rate: 0.001 -Mini-batch(16) descent - stop :15000 iterations Theta: [[-1.03955915 0.01512354 0.00209486]] - Iter: 15000 - Last cost: 0.60 - Duration: 1.18s

在这里插入图片描述上下波动,迭代过程不稳定

对于一些数据,降低学习率之后没有效果,迭代过程依旧不稳定
因此,可能不是模型本身的问题,而是数据本身的问题,尝试着对数据做一些变换,此处对数据进行标准化,用标准化后的数据求解

4.数据标准化

数据标准化问题,当数据发生浮动,先在数据层面上处理,先处理数据,再处理模型

from sklearn import preprocessing as pp scaled_data = orig_data.copy() scaled_data[:, 1:3] = pp.scale(orig_data[:, 1:3])#scale 零均值单位方差,将数据转化为标准正态分布

接下来再来看看经过标准化处理后的数据得到的损失值图

runExpe(scaled_data, theta, n, STOP_ITER, thresh=5000, alpha=0.001) # 0.38

返回

*Scaled data - learning rate: 0.001 -Gradient descent - stop :5000 iterations Theta: [[0.3080807 0.86494967 0.77367651]] - Iter: 5000 - Last cost: 0.38 - Duration: 0.98s

在这里插入图片描述

runExpe(scaled_data, theta, n, STOP_GRAD, thresh=0.02, alpha=0.001) # 0.22

返回

*Scaled data - learning rate: 0.001 -Gradient descent - stop :gradient norm < 0.02 Theta: [[1.0707921 2.63030842 2.41079787]] - Iter: 59422 - Last cost: 0.22 - Duration: 12.18s

在这里插入图片描述

runExpe(scaled_data, theta, 1, STOP_GRAD, thresh=0.002 / 5, alpha=0.001) # 0.22

返回

*Scaled data - learning rate: 0.001 -Stochastic descent - stop :gradient norm < 0.0004 Theta: [[1.1486333 2.79230152 2.56637779]] - Iter: 72596 - Last cost: 0.22 - Duration: 5.63s

在这里插入图片描述

runExpe(scaled_data, theta, 16, STOP_GRAD, thresh=0.002 * 2, alpha=0.001)

返回

*Scaled data - learning rate: 0.001 -Mini-batch(16) descent - stop :gradient norm < 0.004 Theta: [[1.09946538 2.6858268 2.46623512]] - Iter: 63755 - Last cost: 0.22 - Duration: 6.40s

在这里插入图片描述可以发现,经过标准化处理的数据得到的损失值得到明显的改善。


作者:要好好学习呀!



机器学习实战 实战 逻辑回归 梯度下降 学习 回归 梯度 机器学习

需要 登录 后方可回复, 如果你还没有账号请 注册新账号