机器学习实战---逻辑回归梯度上升(更好的理解sigmoid函数的含义并改进)

回顾:

梯度下降

梯度下降和梯度上升区别

一:加载数据和实现sigmoid函数(同梯度下降)

import numpy as np

def loadDataSet():
    data = np.loadtxt("testSet.txt")
    data_X = data[:,0:2]
    data_Y = data[:,-1]

    #注意,后面需要有一个常数项x0,设置为1即可
    data_X = np.c_[np.ones(data_X.shape[0]),data_X]
    return data_X,np.array([data_Y]).T

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

二:实现批量梯度上升(重点)

(一)代码实现

def gradientAsc(data_X,data_Y,iter_Count,alpha): #使用梯度上升,不需要求解代价函数,利用的是概率---我们想求概率最大值    及误差最小   这里就体现了我们之前提及的sigmoid不只是表示0/1,还是一个表示概率的函数
    m,n = data_X.shape
    W = np.ones((n,1))  #初始化权重矩阵    这里直接是n行1列

    for i in range(iter_Count): #进行迭代
        yPred = sigmoid(data_X@W)#开始计算sigmoid值---即预测值
        error = data_Y - yPred  #获取实际标签值和预测值的误差
        W += alpha*data_X.T@error  #其中梯度上升---我们这里的W一直在上升,注意:yPred由于来自sigmoid函数,所以会一直<=1,所以error不会为负值,可能最后拟合出error正好为全0的结果,就是我们要的结果

    return W

(二)结果预测

data_X,data_Y = loadDataSet()
print(gradientAsc(data_X,data_Y,500,0.001))

三:绘制图像决策边界

#绘图图像,画出决策边界
plt.figure()
plt.scatter(data_X[np.where(data_Y==1),1],data_X[np.where(data_Y==1),2],c="red",s=30)
plt.scatter(data_X[np.where(data_Y==0),1],data_X[np.where(data_Y==0),2],c="green",s=30)

#绘制决策边界直线
x = np.linspace(-3,3,100)
y = -(W[0]+W[1]*x)/W[2]
plt.plot(x,y)
plt.show()

四:随机梯度下降法

(一)简陋版随机梯度下降法

def stocGradientAsc(data_X,data_Y,alpha):    #随机梯度算法(简陋版)
    m,n = data_X.shape
    W = np.ones((n,1))
    for i in range(m):  #循环的次数和批量随机梯度下降不一致
        h = sigmoid(data_X[i]@W)   #这里选择一个数据,获取预测(没体现随机)
        error = data_Y[i] - h
        W += alpha*error*(np.array([data_X[i]]).T)

    return W

data_X,data_Y = loadDataSet()
W = stocGradientAsc(data_X,data_Y,150,0.01)

#绘图图像,画出决策边界
plt.figure()
plt.scatter(data_X[np.where(data_Y==1),1],data_X[np.where(data_Y==1),2],c="red",s=30)
plt.scatter(data_X[np.where(data_Y==0),1],data_X[np.where(data_Y==0),2],c="green",s=30)

#绘制决策边界直线
x = np.linspace(-3,3,100)
y = -(W[0]+W[1]*x)/W[2]
plt.plot(x,y)
plt.show()

(二)改进版随机梯度下降法

def stocGradientAsc2(data_X,data_Y,iter_Count,alpha):
    m,n = data_X.shape
    W = np.ones((n,1))

    for j in range(iter_Count): #迭代次数和批量随机梯度保持一致
        dataInt = list(range(m))  #获取全部索引0 - m-1  列表
        for i in range(m):  #迭代数据和批量保持一致
            new_alpha = 4/(1+j+i)+alpha #适当调整alpha参数,随着迭代次数上升,适当降低alpha的值。防止后面的波动。并且避免参数严格下降
            randIdx = int(random.uniform(0,len(dataInt)))   #uniform随机选取范围内的一个实数,所以要int
            h = sigmoid(data_X[randIdx]@W)
            error = data_Y[randIdx] - h
            W += new_alpha*error*np.array([data_X[randIdx]]).T
            del(dataInt[randIdx])
    return W

data_X,data_Y = loadDataSet()
W = stocGradientAsc2(data_X,data_Y,150,0.01)

#绘图图像,画出决策边界
plt.figure()
plt.scatter(data_X[np.where(data_Y==1),1],data_X[np.where(data_Y==1),2],c="red",s=30)
plt.scatter(data_X[np.where(data_Y==0),1],data_X[np.where(data_Y==0),2],c="green",s=30)

#绘制决策边界直线
x = np.linspace(-3,3,100)
y = -(W[0]+W[1]*x)/W[2]
plt.plot(x,y)
plt.show()

五:从疝气病症预测病马的死亡率

(一)数据导入

import random
import numpy as np
import matplotlib.pyplot as plt

def loadDataSet():
    #获取训练集
    data = np.loadtxt("horseColicTraining.txt")
    m,n = data.shape
    trainData_X = data[:,0:n-1]
    trainData_X = np.c_[np.ones(m),trainData_X]
    trainData_Y = np.array([data[:,n-1]]).T   #注意,后面需要有一个常数项x0,设置为1即可

    #获取测试集
    data = np.loadtxt("horseColicTest.txt")
    m, n = data.shape
    TestData_X = data[:, 0:n-1]
    TestData_X = np.c_[np.ones(m),TestData_X]
    TestData_Y = np.array([data[:, n-1]]).T

    return trainData_X,trainData_Y,TestData_X,TestData_Y

(二)改进sigmoid函数

def sigmoid(Z):
    if Z >= 0:
        return 1/(1+np.exp(-Z)) #-Z可能会是极大值,所以导致np.exp(-Z)过大,导致溢出。所以由下面分支处理
    else:   #若是Z<0,那么会出现结果为0。我们只是将上面的式子展开来了。这样,不会出现np.exp(-Z)过大溢出
        return np.exp(Z) / (1+np.exp(Z))

(三)实现预测误差率

def stocGradientAsc2(data_X,data_Y,iter_Count,alpha):
    m,n = data_X.shape
    W = np.ones((n,1))

    for j in range(iter_Count): #迭代次数和批量随机梯度保持一致
        dataInt = list(range(m))  #获取全部索引0 - m-1  列表
        for i in range(m):  #迭代数据和批量保持一致
            new_alpha = 4/(1+j+i)+alpha #适当调整alpha参数,随着迭代次数上升,适当降低alpha的值。防止后面的波动。并且避免参数严格下降
            randIdx = int(random.uniform(0,len(dataInt)))   #uniform随机选取范围内的一个实数,所以要int
            h = sigmoid(data_X[randIdx]@W)
            error = data_Y[randIdx] - h
            W += new_alpha*error*np.array([data_X[randIdx]]).T
            del(dataInt[randIdx])
    return W

def classifyVector(PreDataVec,W):
    h = sigmoid(PreDataVec@W)
    if h > 0.5:
        return 1
    else:
        return 0

def OneTestGetErr(trainData_X,trainData_Y,TestData_X,TestData_Y):
    W = stocGradientAsc2(trainData_X,trainData_Y,500,0.01)
    err = 0
    for i in range(TestData_X.shape[0]):
        if classifyVector(TestData_X[i],W) != TestData_Y[i]:
            err += 1

    return err / TestData_X.shape[0]

def GetAvgErr(trainData_X,trainData_Y,TestData_X,TestData_Y,TestNums=10):
    ErrAvg = 0.0
    for i in range(TestNums):
        err = OneTestGetErr(trainData_X,trainData_Y,TestData_X,TestData_Y)
        print(err)
        ErrAvg += err

    return ErrAvg / TestNums

trainData_X,trainData_Y,TestData_X,TestData_Y = loadDataSet()
print(GetAvgErr(trainData_X,trainData_Y,TestData_X,TestData_Y))

 

posted @ 2020-07-07 21:09  山上有风景  阅读(1291)  评论(0编辑  收藏  举报