机器学习-Logistic回归

机器学习-Logistic回归

本文所有代码来源于《机器学习实战》

梯度下降法

'''
Created on Oct 27, 2010
Logistic Regression Working Module
@author: Peter
'''
'''
注意,本例中默认data在testSet.txt中且有两个attributes,
使用该模型的时候要注意根据实际使用的attributes个数修改代码
'''
from numpy import *

def loadDataSet():#加载数据
    dataMat = []; labelMat = []
    fr = open('testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()
        #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格)或字符序列。
        #注意,在这里为data添加了1的一列
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        #数据有两个attributes
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat

def sigmoid(inX):
    return 1.0/(1+exp(-inX))
#梯度下降方法
def gradAscent(dataMatIn, classLabels):
    #转换为numpy矩阵类型,便于优化和并行计算
    dataMatrix = mat(dataMatIn)             #convert to NumPy matrix
    labelMat = mat(classLabels).transpose() #convert to NumPy matrix
    #将Label转置为列向量
    m,n = shape(dataMatrix)#m行n列
    alpha = 0.001#学习速度
    maxCycles = 500#最大学习步数
    weights = ones((n,1))#将来的输出
    for k in range(maxCycles):              #heavy on matrix operations
        h = sigmoid(dataMatrix*weights)     #matrix mult
        error = (labelMat - h)              #vector subtraction
        weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
    return weights

def plotBestFit(weights):
    import matplotlib.pyplot as plt
    dataMat,labelMat=loadDataSet()#加载源数据,用于画图
    dataArr = array(dataMat)#将data向量化
    n = shape(dataArr)[0] #n为data的个数
    xcord1 = []; ycord1 = []
    xcord2 = []; ycord2 = []
    #给data分类
    for i in range(n):
        if int(labelMat[i])== 1:
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
        else:
            xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    #用不同的颜色画出来
    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
    ax.scatter(xcord2, ycord2, s=30, c='green')
    #arange([start,] stop[, step,], dtype=None)
    #根据start与stop指定的范围以及step设定的步长,生成一个 ndarray。
    '''
    这一段是在干什么呢?其实就是想要画一条直线出来,但是只能画点,由点组成线
    '''
    x = arange(-3.0, 3.0, 0.1)
    y = (-weights[0]-weights[1]*x)/weights[2]
    ax.plot(x, y)
    plt.xlabel('X1'); plt.ylabel('X2');
    plt.show()

随机梯度下降

对于⼤样本,梯度下降是很耗费时间的,因为它每⼀次都需要对所有样本进⾏求和。对于这种⽅法,我们也叫它批量梯度下降⽅法(Batch gradient descent) 。

改进之后,我们只需要每次看⼀个样本就可以了,这大大节省了计算资源。同时,随机梯度下降也是一个在线算法,可以实现在线学习(Online learning),在新数据到来时就完成参数更新而不需要重新计算整个数据集。

#改进的随机梯度下降法
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    m,n = shape(dataMatrix)
    weights = ones(n)   #initialize to all ones
    for j in range(numIter):#对样本迭代150次
        dataIndex = list(range(m))#dataIndex保存了所有在本次迭代中还没有使用过的data
        for i in range(m):
            '''
            改进1:学习速度在每次迭代后都会调整,越往后学习速度越小,这会缓解在最优点附近的波动.
            由于我们在alpha之后加了一个常数,这使得alpha即使再迭代也不会减小到0.
            在降低alpha的函数中,j是迭代次数,i是data下标,这样可以避免参数的严格下降
            '''
            alpha = 4/(1.0+j+i)+0.0001    #apha decreases with iteration, does not
            #改进2:随机选择用来计算的data
            randIndex = int(random.uniform(0,len(dataIndex)))#go to 0 because of the constant
            h = sigmoid(sum(dataMatrix[randIndex]*weights))
            error = classLabels[randIndex] - h
            weights = weights + alpha * error * dataMatrix[randIndex]
            del(dataIndex[randIndex])
    return weights

附上完整实现+测试代码:

'''
Created on Oct 27, 2010
Logistic Regression Working Module
@author: Peter
'''
'''
注意,本例中默认data在testSet.txt中且有两个attributes,
使用该模型的时候要注意根据实际使用的attributes个数修改代码
'''
from numpy import *

def loadDataSet():#加载数据
    dataMat = []; labelMat = []
    fr = open('testSet.txt')
    for line in fr.readlines():
        lineArr = line.strip().split()
        #Python strip() 方法用于移除字符串头尾指定的字符(默认为空格)或字符序列。
        #注意,在这里为data添加了1的一列
        dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])
        #数据有两个attributes
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat

def sigmoid(inX):
    return 1.0/(1+exp(-inX))
#梯度下降方法
def gradAscent(dataMatIn, classLabels):
    #转换为numpy矩阵类型,便于优化和并行计算
    dataMatrix = mat(dataMatIn)             #convert to NumPy matrix
    labelMat = mat(classLabels).transpose() #convert to NumPy matrix
    #将Label转置为列向量
    m,n = shape(dataMatrix)#m行n列
    alpha = 0.001#学习速度
    maxCycles = 500#最大学习步数
    weights = ones((n,1))#将来的输出
    for k in range(maxCycles):              #heavy on matrix operations
        h = sigmoid(dataMatrix*weights)     #matrix mult
        error = (labelMat - h)              #vector subtraction
        weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
    return weights

def plotBestFit(weights):
    import matplotlib.pyplot as plt
    dataMat,labelMat=loadDataSet()#加载源数据,用于画图
    dataArr = array(dataMat)#将data向量化
    n = shape(dataArr)[0] #n为data的个数
    xcord1 = []; ycord1 = []
    xcord2 = []; ycord2 = []
    #给data分类
    for i in range(n):
        if int(labelMat[i])== 1:
            xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
        else:
            xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
    fig = plt.figure()
    ax = fig.add_subplot(111)
    #用不同的颜色画出来
    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
    ax.scatter(xcord2, ycord2, s=30, c='green')
    #arange([start,] stop[, step,], dtype=None)
    #根据start与stop指定的范围以及step设定的步长,生成一个 ndarray。
    '''
    这一段是在干什么呢?其实就是想要画一条直线出来,但是只能画点,由点组成线
    '''
    x = arange(-3.0, 3.0, 0.1)
    y = (-weights[0]-weights[1]*x)/weights[2]
    ax.plot(x, y)
    plt.xlabel('X1'); plt.ylabel('X2');
    plt.show()
#随机梯度下降法,只对整个数据集迭代了一次,显然不够
def stocGradAscent0(dataMatrix, classLabels):
    m,n = shape(dataMatrix)
    alpha = 0.01
    weights = ones(n)   #initialize to all ones
    for i in range(m):
        h = sigmoid(sum(dataMatrix[i]*weights))
        error = classLabels[i] - h
        #这里其实不是真正的随机,样本是按顺序取的
        weights = weights + alpha * error * dataMatrix[i]
    return weights
#改进的随机梯度下降法
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
    m,n = shape(dataMatrix)
    weights = ones(n)   #initialize to all ones
    for j in range(numIter):#对样本迭代150次
        dataIndex = list(range(m))#dataIndex保存了所有在本次迭代中还没有使用过的data
        for i in range(m):
            '''
            改进1:学习速度在每次迭代后都会调整,越往后学习速度越小,这会缓解在最优点附近的波动.
            由于我们在alpha之后加了一个常数,这使得alpha即使再迭代也不会减小到0.
            在降低alpha的函数中,j是迭代次数,i是data下标,这样可以避免参数的严格下降
            '''
            alpha = 4/(1.0+j+i)+0.0001    #apha decreases with iteration, does not
            #改进2:随机选择用来计算的data
            randIndex = int(random.uniform(0,len(dataIndex)))#go to 0 because of the constant
            h = sigmoid(sum(dataMatrix[randIndex]*weights))
            error = classLabels[randIndex] - h
            weights = weights + alpha * error * dataMatrix[randIndex]
            del(dataIndex[randIndex])
    return weights

dataArr,labelMat=loadDataSet()
weights=gradAscent(dataArr,labelMat)
print("梯度下降法:")
#getA()是numpy的一个函数,作用是将矩阵转成一个ndarray,getA()函数和mat()函数的功能相反,是将一个矩阵转化为数组。
plotBestFit(weights.getA())
print("随机梯度下降法")
weights2=stocGradAscent0(array(dataArr),labelMat)
plotBestFit(weights2)
print("一次随机梯度下降很可能是得不到最优结果的")
print("改进的随机梯度下降法")
weights3=stocGradAscent1(array(dataArr),labelMat)
plotBestFit(weights3)
posted @ 2019-10-12 11:00  别再闹了  阅读(471)  评论(0编辑  收藏  举报