1. 基本知识
一、Logistic回归的一般过程
1、收集数据:采用任意方法收集数据
2、准备数据:需要进行距离计算,数据类型为数值型
3、分析数据:采用任意方法对数据进行分析
4、训练算法:寻找最佳的分类回归系数
5、测试算法:一旦训练步骤未完成,分类将会很快
6、使用算法:first,我们需要输入一些数据,将其转换成对应的结构化数值。second,基于训练好的回归系数,进行简单回归计算,并判断属于哪一个类别。 third,可以在输出的类别上做其他分析工作
优点:计算代价不高,易于理解和实现
缺点:容易欠拟合,分类精度可能不高
使用数据类型:数值型和标称型数据
sigmoid函数sigmoid=1/(1+exp(-z))
为了实现logistic回归,在每一个特征上都乘以一个回归系数,然后把所有结果值相加,将总和带入sigmoid函数中,
进而得到一个范围在0~1之间的数值。任何大于0.5的数据分入1类,小于0.5分入0类。
二、基于最优化方法的最佳回归系数确定
sigmoid函数输入为z=w0x0+……+wnxn,其中w为要寻找的最佳参数。
梯度上升法
梯度下降法
训练算法:使用梯度上升找到最佳参数
伪代码:每个回归系数初始化为1
重复R次:
计算整个数据集的梯度
使用aipha*gradient更新回归系数的向量
返回回归系数
2.代码
优化算法
# -*- coding: utf-8 -*-
"""
Created on Jan 10 2018
@author: lixu
"""
from numpy import *
import matplotlib.pyplot as plt
# 逻辑回归梯度上升优化算法
def loadDataSet():# 逐行读取文件
dataMat=[];labelMat=[]
fr=open("testSet")
for line in fr.readlines():
lineArr=line.strip().split()
dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])# 将x0值设为1.0
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
def sigmoid(inX):
return 1.0/(1+exp(-inX))
def gradAscent(dataMatIn,classLabels): # dataMatIn是100*3数组,X0,X1,X2;classLabels是100*1的行向量,类别标签
dataMatrix=mat(dataMatIn)
labelMat=mat(classLabels).transpose()
m,n=shape(dataMatrix)
alpha=0.001 # 步长
maxCycles=500
weights=ones((n,1))
for k in range(maxCycles):
h=sigmoid(dataMatrix*weights)
error=labelMat-h
weights=weights+alpha*dataMatrix.transpose()*error# 求解回归系数
return weights
# 画出数据集和Logistic回归最佳拟合直线的函数
def plotBestFit(weights):
dataMat,labelMat=loadDataSet()
dataArr=array(dataMat)
n=shape(dataArr)[0]
xcord1=[]
ycord1=[]
xcord2=[]
ycord2=[]
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')
x=arange(-3.0,3.0,0.1)
# 此处设置了Sigmoid的z为0,因为0是两个分类的分界处
# 即:0=w0x0+w1x1+w2x2
# 注意:x0=1,x1=x,解出x2=y
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)
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)
for j in range(numIter):
dataIndex=range(m)
for i in range(m):
alpha=4/(1.0+j+i)+0.01 # alpha随着迭代次数增加逐渐减小,永远不会减小到零
randIndex=int(random.uniform(0,len(dataIndex)))
# random.uniform的函数原型为:random.uniform(a, b),用于生成一个指定范围内的随机符点数,两个
# 参数其中一个是上限,一个是下限。如果a > b,则生成的随机数n: a <= n <= b。如果 a <b, 则 b <=
# n <= a。随机选取样本来更新系数
h=sigmoid(sum(dataMatrix[randIndex]*weights))
error=classLabels[randIndex]-h
weights = weights + alpha * error * dataMatrix[randIndex]
return weights
示例:使用Logistic回归估计马疝病的死亡率
收集数据:给定数据文件。
准备数据:用Python解析文本文件并填充缺失值。
分析数据:可视化并观察数据。
训练算法:使用优化算法,找到最佳的系数。
测试算法:为了量化回归效果,需要观察错误率,根据错误率决定是否回退到训练阶段,通过改变迭代的次数和步长等参数来得到更好的回归系数。
使用算法:实现一个简单的命令行程序来收集马的症状并输出预测结果并非难事,这可以作为留给读者的一道习题。
另外需要说明的是,除了部分指标主观和难以测量外,该数据还存在一个问题,数据集中有30%的值是缺失的。下面将首先介绍如何处理数据集中的数据缺失问题,然后利用Logistic回归和随机梯度上升算法来预测病马的生死。
准备数据;处理数据中的缺失值
数据中的缺失值是个非常棘手的问题,有很多文献都致力于解决这个问题。下面给出一些可选的做法:
[1 ] 使用可用特征的均值来填补缺失值;
[2 ] 使用特殊值来填补缺失值,如-1;
[ 3] 忽略所有缺失的样本;
[4 ] 使用相似样本的均值添补缺失值;
[5 ] 使用另外的机器学习算法预测缺失值。
现在,我们对后面用到的数据集进行预处理,使其可以顺利地使用分类算法。在预处理阶段需要做两件事:第一,所有的缺失值必须用一个实数值来替换,因为我们使用的Numpy数组不允许包含缺失值。这里选择实数0来替换所有缺失值,恰好能适用于Lodistic回归。这样做的原因在于,我们需要一个在更新时不会影响系数的值。回归系数的更新公式如下:
weights=weights+alpha∗error∗dataMatrix[ranIndex]
很明显,如果dataMatrix的某特征对应值为0,那么该特征的系数将不做更新,即weights=weights。另外,由于sigmoid(0)=0.5对结果的预测不具有任何倾向性,因为上述做法也不会对误差项造成任何影响,完美!
预处理的第二件事是,如果发现一条数据的类别标签已经缺失,纳闷我们的简单做法就是将该条数据丢弃。这是因为类别标签和特征不同,很难确定采用某个合适的值来替换。采用Logistic回归进行分类时,这种做法是合理的,而如果采用类似kNN的方法就可能不太可行。
3.示例代码
# 从疝气病症预测病马的死亡率
# logistic回归分类函数
def classifyVector(inX,weights):
prob=sigmoid(sum(inX*weights))
if prob>0.5: return 1.0
else: return 0.0
def colicTest():
frTrain=open("horseColicTraining")
frTest=open("horseColicTest")
trainingSet=[]
trainingLabels=[]
for line in frTrain.readlines():
currLine=line.strip().split('\t')
lineArr=[]
for i in range(21):
lineArr.append(float(currLine[i]))
trainingSet.append(lineArr)
trainingLabels.append(float(currLine[21]))
traingWeights=stocGradAscent1(array(trainingSet),trainingLabels,500)
errorCount=0
numTestVec=0.0
for line in frTest.readlines():
numTestVec+=1.0
currLine=line.strip().split('\t')
lineArr=[]
for i in range(21):
lineArr.append(float(currLine[i]))
if int(classifyVector(array(lineArr),traingWeights))!=int(currLine[21]):
errorCount+=1
errorRate=(float(errorCount)/numTestVec)
print"The errorRate of this test is :%f" % errorRate
return errorRate
def multiTest():
numTests=10
errorSum=0.0
for k in range(numTests):
errorSum += colicTest()
print"After %d iterations the average error rate is:%f" % (numTests,errorSum/float(numTests))
4.运行代码
# -*- coding: utf-8 -*-
"""
Created on Jan 10 2018
@author: lixu
"""
from numpy import *
import logRegres
# 逻辑回归梯度上升优化算法
dataArr,labelMat= logRegres.loadDataSet()
print logRegres.gradAscent(dataArr, labelMat)
# 画出数据集和Logistic回归最佳拟合直线的函数
weights=logRegres.gradAscent(dataArr,labelMat)
logRegres.plotBestFit((weights.getA()))
# 随机梯度上升法
weights=logRegres.stocGradAscent0(array(dataArr),labelMat)
logRegres.plotBestFit((weights))
# 改进的随机梯度上升算法
weights=logRegres.stocGradAscent1(array(dataArr),labelMat)
logRegres.plotBestFit((weights))
# logistic回归分类函数
logRegres.multiTest()
5.结果展示
希望对大家有所帮助。