一、概念:
具体逻辑已经在机器学习(二)逻辑回归说明
二、算法实现
《机器学习实战》中,使用的代价函数是线性回归的代价函数:
书中的叫法是梯度上升,但更多但材料用“梯度下降”的叫法
import numpy as np
def loadDataSet():
dataMat=[]
labelMat=[]
fr=open('/Users/xxxx/Downloads/machinelearninginaction-master/Ch05/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]))
return dataMat,labelMat
def sigmoid(inX):
return 1.0/(1+np.exp(-inX))
def gradAscent(dataMatIn,classLabels):
dataMatrix=np.mat(dataMatIn) #转换成Numpy矩阵形式
labelMat=np.mat(classLabels).transpose()
m,n=np.shape(dataMatrix)
alpha=0.001
maxCycles=500
weights=np.ones((n,1))
for k in range(maxCycles):
h=sigmoid(dataMatrix*weights)
error=(labelMat-h)
weights=weights+alpha*dataMatrix.transpose()*error #线性回归代价函数
return weights
分析:
matrix.getA()函数是将matrix转换为ndarray类型
上面的梯度下降算法是拿整个数据集进行矩阵运算,迭代次数是500次。该方法处理少量几百个左右的数据集还好,当数据集成千上万上亿时,该算法复杂度太高了。
改进方法: 采用随机梯度下降,对每个数据样本进行计算:
随机梯度下降是在线学习算法,一次处理所有数据被称作为“批处理”
def stocGradAscent0(dataMatrix, classLabels):
dataMatrix=np.array(dataMatrix)
m,n = np.shape(dataMatrix)
alpha = 0.01
weights = np.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
可以看到,拟合出来的分类器错分了三分之一的数据样本。
我们在整个数据集上迭代运行可以知道,一开始训练出来的参数w变化大,随着迭代次数的增加趋于稳定。
所以一开始的训练步伐可以大一点,随后慢慢减小步伐。
对随机梯度下降进行改进:
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = np.shape(dataMatrix)
weights = np.ones(n) #initialize to all ones
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001 #apha decreases with iteration, does not
randIndex = int(np.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