机器学习入门(引用)____2.逻辑回归实现

导包

import numpy as np  	  	
import pandas as pd       #读取数据时使用
import matplotlib.pyplot as plt #画图中会用到
%matplotlib inline  #在jupyter中运行,需要让图片能够在jupyter中显示

导入数据

这份数据包含100个样本,每个样本包含三列,分别代表两门考试成绩和能否被学校录取(1表示录取,0表示不录取)

import os 
path = 'data'+os.sep+'LogiReg_data.txt'
pdData=pd.read_csv(path,header=None,names=['Exam 1','Exam 2','Admitted'])
pdData.head()

使用pandas读取数据,并显示前五行
在这里插入图片描述

在图表中显示数据

positive = pdData[pdData['Admitted']==1]
negative = pdData[pdData['Admitted']==0]
fig,ax = plt.subplots(figsize=(10,5))
#绘制散点图 其中前两个参数为x,y坐标,s为散点大小,c为颜色,marker为用什么图案标志,label就是描述了
ax.scatter(positive['Exam 1'],positive['Exam 2'],s=30,c='b',marker='o',label='Admitted') 
ax.scatter(negative['Exam 1'],negative['Exam 2'],s=30,c='r',marker='x',label='Not Admitted')
ax.legend()
ax.set_xlabel('Exam 1 Score')
ax.set_ylabel('Exam 2 Score')

将数据分为已录取和未录取两组,并通过pyplot显示
在这里插入图片描述

实现逻辑回归流程

1.实现sigmod函数
2.将预测模型代入sigmod函数求得概率值
3.根据计算得到的预测结果与真实结果作差值得到损失函数
4.实现梯度下降函数
5.通过梯度下降函数一步一步更新参数,得到合适的结果
6.计算准确率

sigmod函数

函数原型:
在这里插入图片描述

def sigmoid(z):
    return 1/(1+np.exp(-z))

sigmod在pyplot中的显示:

nums = np.arange(-10,10,step=1)
fig,ax = plt.subplots(figsize=(12,4))
ax.plot(nums,sigmoid(nums),'r')

在这里插入图片描述

实现预测模型

将预测模型放入sigmod函数中得到概率值:
在这里插入图片描述

def model(X,theta):
    return sigmoid(np.dot(X,theta.T))

进行简单的数据处理

模型:
在这里插入图片描述
将数据中插入一列作为常数项参数

pdData.insert(0,'Ones',1)

将数据分为X与y两部分,y为最终结果

orig_data = pdData.as_matrix()
cols = orig_data.shape[1]
X = orig_data[:,:cols-1]  #取得所有行除最后一列外所有列
y = orig_data[:,cols-1:cols]#取得所有行的每行最后一列
theta = np.zeros([1,3]) #初始化模型参数,为一个1行三列的数据

X前五行:

X[:5]

在这里插入图片描述
y前五行:

y[:5]

在这里插入图片描述
参数数据

theta

在这里插入图片描述

求解损失

在这里插入图片描述
此时要求对数似然尽可能的大,为方便之后用梯度下降求解,在前面加-号变为使l( θ \theta θ)尽可能小。
经过转换变为
在这里插入图片描述
损失函数代码:

将D()函数分为左右两部分,进行简单的矩阵运算得到结果

def cost(X, y, theta):
    left = np.multiply(-y, np.log(model(X, theta)))
    right = np.multiply(1 - y, np.log(1 - model(X, theta)))
    return np.sum(left - right) / (len(X))

得到损失

cost(X, y, theta)

梯度函数

对每一个参数进行求偏导,得到如下式子:其中 x i j x_{ij} xij中i代表代表第i个样本,j代表第j个参数对应x
在这里插入图片描述

def gradient(X, y, theta):
    grad = np.zeros(theta.shape)
    error = (model(X, theta)- y).ravel()
    for j in range(len(theta.ravel())): #ravel作用是“拉平”数据,将多维变一维,方便统计参数个数
        term = np.multiply(error, X[:,j])#上式的代码形式
        grad[0, j] = np.sum(term) / len(X)#计算出第j个参数的偏导
    
    return grad#返回梯度结果。将每一个参数都进行了偏导求解

设定不同梯度下降方法

0表示达到一定迭代次数停止梯度下降
1表示损失低到一定程度停止梯度下降
2表示当梯度变化降到某一点时停止

STOP_ITER = 0 #按照迭代次数
STOP_COST = 1 #按照损失值
STOP_GRAD = 2 #按照梯度下降方式

def stopCriterion(type, value, threshold):
    #设定三种不同的停止策略
    if type == STOP_ITER:        return value > threshold
    elif type == STOP_COST:      return abs(value[-1]-value[-2]) < threshold
    elif type == STOP_GRAD:      return np.linalg.norm(value) < threshold

随机从样本中获取数据

import numpy.random
#洗牌
def shuffleData(data):
    np.random.shuffle(data)
    cols = data.shape[1]
    X = data[:, 0:cols-1]
    y = data[:, cols-1:]
    return X, y

梯度下降求解

函数参数分别为数据,模型参数,每次批量迭代大小,停止类型,阈值和学习率

import time
def descent(data,theta,batchSize,stopType,thresh,alpha):#thresh 阈值
    #梯度下降求解
    init_time = time.time()
    i = 0#迭代次数
    k = 0 #batch
    X,y = shuffleData(data)
    grad=np.zeros(theta.shape)
    costs = [cost(X,y,theta)]
    while True:#进行循环迭代
        grad = gradient(X[k:k+batchSize],y[k:k+batchSize],theta)
        k += batchSize
        if k >= n:#拿完所有数据时洗牌后重新拿
            k = 0
            X,y =shuffleData(data)
        theta = theta-alpha*grad#进行梯度下降
        costs.append(cost(X,y,theta))#将这一步得到的损失值放入损失列表方便之后进行表格绘制
        i+=1
        if stopType == STOP_ITER: value = i
        elif stopType == STOP_COST: value = costs
        elif 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):
    #import pdb; pdb.set_trace();
    theta, iter, costs, grad, dur = descent(data, theta, batchSize, stopType, thresh, alpha)
    name = "Original" if (data[:,1]>2).sum() > 1 else "Scaled"
    name += " 学习率: {} - ".format(alpha)
    if batchSize==n: strDescType = "全梯度"
    elif batchSize==1:  strDescType = "随机"
    else: strDescType = "小批量 ({})".format(batchSize)
    name += strDescType + " 停止方式: "
    if stopType == STOP_ITER: strStop = "{} 迭代".format(thresh)
    elif stopType == STOP_COST: strStop = "损失 < {}".format(thresh)
    else: strStop = "梯度下降率 < {}".format(thresh)
    name += strStop
    print ("***{}\n参数: {} -  次数: {} - 最终损失: {:03.2f} - 时间: {:03.2f}s".format(
        name, theta, iter, costs[-1], dur))
    fig, ax = plt.subplots(figsize=(12,4))
    
    ax.plot(np.arange(len(costs)), costs, 'r')
    ax.set_xlabel('迭代次数')
    ax.set_ylabel('损失')
    ax.set_title(name.upper() + ' - 损失 vs. 迭代')
    return theta

不同梯度下降方式的比较

全样本下处理

5000次迭代

from pylab import mpl
mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
n=100
runExpe(orig_data, theta, n, STOP_ITER, thresh=5000, alpha=0.000001)

在这里插入图片描述

按照损失停止方式进行的迭代

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

在这里插入图片描述

按照梯度下降阈值方式进行迭代

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

在这里插入图片描述

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

在这里插入图片描述

比较

停止方式迭代次数最终损失耗时
5000次迭代50000.631.53s
损失改变值低于0.000001约11w次0.3832.68s
梯度下降率<0.05约4w次0.4912.89s
梯度下降率<0.02越6w次0.2220.31s

单样本下随机梯度下降

5000次迭代

runExpe(orig_data, theta, 1, STOP_ITER, thresh=5000, alpha=0.001)

在这里插入图片描述
我们可以发现在单一样本随机梯度下损失很不稳定

增加迭代次数并降低学习率

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

在这里插入图片描述
在增加了迭代次数并降低学习率后虽然还会有波动,但整体趋于下降趋势

按照梯度下降阈值方式进行迭代

from sklearn import preprocessing as pp

scaled_data = orig_data.copy()
scaled_data[:, 1:3] = pp.scale(orig_data[:, 1:3])
runExpe(scaled_data, theta, n, STOP_GRAD, thresh=0.02, alpha=0.001)

这里使用sklearn对数据进行了归一化处理即数据预处理(之后的文章中会讲到),方能得到较理想的结果(不将其放入最终比较中)
在这里插入图片描述

批量样本下处理

5000次迭代

runExpe(scaled_data, theta, 16, STOP_ITER, thresh=5000, alpha=0.001)

在这里插入图片描述

按照损失停止方式进行的迭代

runExpe(scaled_data, theta, 16, STOP_COST, thresh=0.000001, alpha=0.001)

在这里插入图片描述

按照梯度下降阈值方式进行迭代

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

在这里插入图片描述

比较

停止方式迭代次数最终损失耗时
5000次迭代50000.380.61s
损失改变值低于0.000001约566次0.620.1s
梯度下降率<0.05约4w次0.4911.79s

总结

通过比较不难发现,全样本的速度执行速度较慢,而单一样本则波动太大,批量样本执行速度较快。
三种停止方式由于与样本和实验次数有关,不能够直接下定论

数据文件

链接:https://pan.baidu.com/s/1Fca58KeBnOzjMtK42rnm-g
提取码:hrj6

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值