Logistic回归之梯度上升优化算法(二)

Logistic回归之梯度上升优化算法(二)

有了上一篇的知识储备,这一篇博客我们就开始Python3实战

1、数据准备

数据集:数据集下载

数据集内容比较简单,我们可以简单理解为第一列X,第二列Y,第三列是分类标签。根据标签的不同,对这些数据点进行分类。

import matplotlib.pyplot as plt
import numpy as np

'''
函数说明:加载数据
Parameters:
    None
Returns:
    dataMat - 数据列表
    labelMat - 标签列表
'''
def loadDataSet():
    dataMat = []  # 创建数据列表
    labelMat = []  # 创建标签列表
    fr = open('testSet.txt')  # 打开文件
    for line in fr.readlines():
        lineArr = line.strip().split()  # 去回车,放入列表
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])  # 添加数据
        labelMat.append(int(lineArr[2]))  # 添加标签
    fr.close()  # 关闭文件
    return dataMat, labelMat


'''
函数说明:绘制数据集
Parameters:
    None
Returns:
    None
'''
def plotDataSet():
    dataMat, labelMat = loadDataSet()  # 加载数据集
    dataArr = np.array(dataMat)  # 转换成numpy的array数组
    n = np.shape(dataMat)[0]  # 数据个数,即行数
    xcord1 = [] ; ycord1 = []  # 正样本
    xcord2 = [] ; ycord2 = []  # 负样本
    for i in range(n):
        if int(labelMat[i]) == 1: #1为正样本
            xcord1.append(dataMat[i][1])
            ycord1.append(dataMat[i][2])
            # xcord1.append(dataArr[i, 1]);ycord1.append(dataArr[i, 2])
        else:                     #0为负样本
            xcord2.append(dataMat[i][1])
            ycord2.append(dataMat[i][2])
            # xcord2.append(dataArr[i, 1]);ycord2.append(dataArr[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)   #添加subplot
    ax.scatter(xcord1,ycord1,s=20,c='red',marker = 's', alpha=.5,label ='1') #绘制正样本
    ax.scatter(xcord2,ycord2,s=20,c='green',marker = 's', alpha=.5,label ='0') #绘制正样本
    plt.title('DataSet') #绘制title
    plt.xlabel('x'); plt.ylabel('y') #绘制label
    plt.legend()
    plt.show()

if __name__ == '__main__':
    plotDataSet()

运行结果如下:

2、训练算法:使用梯度上升找到最佳参数

代码如下:

import matplotlib.pyplot as plt
import numpy as np

'''
函数说明:加载数据
Parameters:
    None
Returns:
    dataMat - 数据列表
    labelMat - 标签列表
'''
def loadDataSet():
    dataMat = []  # 创建数据列表
    labelMat = []  # 创建标签列表
    fr = open('testSet.txt')  # 打开文件
    for line in fr.readlines():
        lineArr = line.strip().split()  # 去回车,放入列表
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])  # 添加数据
        labelMat.append(int(lineArr[2]))  # 添加标签
    fr.close()  # 关闭文件
    return dataMat, labelMat
'''
函数说明:sigmodi函数
Paremeters:
    inX - 数据
Returns:
    sigmoid函数
'''
def sigmoid(inX):
    return 1.0/(1 + np.exp(-inX))

'''
函数说明:梯度上升算法
Parameters:
    dataMatIn - 数据集
    classLables - 数据标签
Returns:
    weights.getA() - 求得的权重数组(最优参数)
'''
def gradAscent(dataMatIn, classLables):
    dataMatrix = np.mat(dataMatIn)  #转换成numpy的mat
    # print(dataMatrix)
    labelMat =  np.mat(classLables).transpose() #转换成numpy的mat,并进行转置
    # print(labelMat)
    m, n =np.shape(dataMatrix)#返回dataMatrix的大小。m为行,n为列
    alpha = 0.001  #移动补偿,也就是学习速率,控制更新的幅度
    maxCycles = 500 #最大迭代次数
    weights = np.ones((n,1))
    # print(weights)
    for k in range(maxCycles):
        h = sigmoid(dataMatrix *weights) #梯度上升矢量公式
        # print(h)
        #权重系数计算公式
        error = labelMat - h
        weights = weights + alpha * dataMatrix.transpose()*error
    return weights.getA()  #将矩阵转换为数组,返回权重数组



if __name__ == '__main__':
    np.set_printoptions(suppress=True)
    dataMat,labelMat = loadDataSet()
    print(gradAscent(dataMat,labelMat))

其中在gradAscent()函数中的循环里有一个训练参数的计算公式,这边我不做推导直接给出。推导网址

运行结果如图所示:

到此我们已经求解出回归系数[w0,w1,w2]。通过求解出的参数,我们可以确定不同类别数据之间的分隔线,画出决策边界。

3、绘制决策边界

代码如下:

import matplotlib.pyplot as plt
import numpy as np

'''
函数说明:加载数据
Parameters:
    None
Returns:
    dataMat - 数据列表
    labelMat - 标签列表
'''
def loadDataSet():
    dataMat = []  # 创建数据列表
    labelMat = []  # 创建标签列表
    fr = open('testSet.txt')  # 打开文件
    for line in fr.readlines():
        lineArr = line.strip().split()  # 去回车,放入列表
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])  # 添加数据
        labelMat.append(int(lineArr[2]))  # 添加标签
    fr.close()  # 关闭文件
    return dataMat, labelMat


'''
函数说明:绘制数据集
Parameters:
    None
Returns:
    None
'''
def plotDataSet(weights):
    dataMat, labelMat = loadDataSet()  # 加载数据集
    dataArr = np.array(dataMat)  # 转换成numpy的array数组
    n = np.shape(dataMat)[0]  # 数据个数,即行数
    xcord1 = [] ; ycord1 = []  # 正样本
    xcord2 = [] ; ycord2 = []  # 负样本
    for i in range(n):
        if int(labelMat[i]) == 1: #1为正样本
            xcord1.append(dataMat[i][1])
            ycord1.append(dataMat[i][2])
            # xcord1.append(dataArr[i, 1]);ycord1.append(dataArr[i, 2])
        else:                     #0为负样本
            xcord2.append(dataMat[i][1])
            ycord2.append(dataMat[i][2])
            # xcord2.append(dataArr[i, 1]);ycord2.append(dataArr[i, 2])
    fig = plt.figure()
    ax = fig.add_subplot(111)   #添加subplot
    ax.scatter(xcord1,ycord1,s=20,c='red',marker = 's', alpha=.5,label ='1') #绘制正样本
    ax.scatter(xcord2,ycord2,s=20,c='green',marker = 's', alpha=.5,label ='0') #绘制正样本
    x = np.arange(-3.0,3.0,0.1)
    y = (-weights[0] - weights[1] * x) / weights[2]
    ax.plot(x,y)
    plt.title('DataSet') #绘制title
    plt.xlabel('x'); plt.ylabel('y') #绘制label
    plt.legend()
    plt.show()


'''
函数说明:sigmodi函数
Paremeters:
    inX - 数据
Returns:
    sigmoid函数
'''
def sigmoid(inX):
    return 1.0/(1 + np.exp(-inX))

'''
函数说明:梯度上升算法
Parameters:
    dataMatIn - 数据集
    classLables - 数据标签
Returns:
    weights.getA() - 求得的权重数组(最优参数)
'''
def gradAscent(dataMatIn, classLables):
    dataMatrix = np.mat(dataMatIn)  #转换成numpy的mat
    # print(dataMatrix)
    labelMat =  np.mat(classLables).transpose() #转换成numpy的mat,并进行转置
    # print(labelMat)
    m, n =np.shape(dataMatrix)#返回dataMatrix的大小。m为行,n为列
    alpha = 0.001  #移动补偿,也就是学习速率,控制更新的幅度
    maxCycles = 500 #最大迭代次数
    weights = np.ones((n,1))
    # print(weights)
    for k in range(maxCycles):
        h = sigmoid(dataMatrix *weights) #梯度上升矢量公式
        # print(h)
        error = labelMat - h
        weights = weights + alpha * dataMatrix.transpose()*error
    return weights.getA()  #将矩阵转换为数组,返回权重数组



if __name__ == '__main__':
    np.set_printoptions(suppress=True)
    dataMat,labelMat = loadDataSet()
    weights = gradAscent(dataMat,labelMat)
    plotDataSet(weights)

其中绘制的分隔线设置了sigmoid函数为0,回忆上一篇内容,0是两个分类的分解出,因此我们设定\large 0 = w_{0}x_{0}+w_{1}x_{1}+w_{2}x_{2},然后接触X2和X1的关系式(及分割线的方程,注意X0=1)。

运行结果如下:

从分类结果可以看出,还有几个点是错的。但是这个方法徐良大量的计算(300次乘法),在下一篇文章会对算法稍作改进。

4、总结

Logistic回归的一般过程:

  • 收集数据:采用任一方法收集数据
  • 准备数据:需要距离计算,因此要求数据类型为数值型
  • 分析数据:采用任意方法对数据进行分析
  • 训练算法:大部分时间用于训练,为了找到最佳的分类回归洗漱
  • 测试算法:训练步骤完成,分类将会很快。

参考文献:

猜你喜欢

转载自blog.csdn.net/qq_25174673/article/details/83749836
今日推荐