源代码与资源文件
#本文适用读者:#
了解朴素贝叶斯,并且python version 为 3.x
##一、利用Logistic回归进行分类的主要思想:
其根据现有数据对分类边界线建立回归公式,以此进行分类.这里的"回归"一词源于最佳拟合,表示要找到最佳拟合参数集.
##二、优缺点:
优点:计算代价不高,易于理解与实现
缺点:容易欠拟合,分类精度可能不高
使用数据类型:数值型和标称型数据
##三、数学基础:
###Sigmoid函数:
当z为0时,Sigmoid函数值为0.5.随着x的增大,对应的Sigmoid值将逼近与1:而随着x的减小,Sigmoid值将逼近与0,如下图:
###分类器的实现:
我们在每个特征上乘以一个回归系数,然后把所有结果值相加,将这个总值代入Sigmoid函数中,进而得到一个范围在0~1之间的数值.最后,结果大于0.5的数据被归入1类,小于0.5的就被归入0类.所以Logistic回顾也可以看成是一种概率估计
###梯度上升法:
如果梯度记为▽,则函数f(x,y)的梯度由下式表示:
梯度意味着x的变化量是f(x,y)对x的偏导,y的变化量是f(x,y)对y的偏导.其中,函数f(x,y)必须要在待计算的点上有定义并且可微,举一个栗子:
梯度上升算法到达每个点后都会重新估计移动的方向.即重新计算偏导. 从P0开始, 计算完该点的梯度, 函数就根据梯度移动到下一点P1. 在P1点, 梯度在此被重新计算, 并沿新的梯度方向移动到P2. 如此循环迭代,知道满足停止条件. 迭代过程中, 梯度算子总是保证我们能选取到最佳的移动方向
##四、程序清单:
###logistic回归梯度上升优化算法:
将以下代码写入logRegres.py文件中
import numpy as np
import matplotlib.pyplot as plt
#loadDataSet函数用于读取txt数据文档,将文档中数据处理成两个向量dataMat,与labelMat
def loadDataSet():
dataMat = []; labelMat = []
fr = open('testSet.txt')
for line in fr.readlines():
lineArr = line.strip().split() #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))
#gradAscent函数
def gradAscent(dataMatIn, classLabels):
#转换为NumPy矩阵数据类型
dataMatrix = np.mat(dataMatIn)
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
###图形化程序:
将以下代码写入logRegres.py文件中
def plotBestFit(wei):
dataMat,labelMat = loadDataSet()
dataArr = np.array(dataMat)
n = np.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 = np.arange(-3.0, 3.0, 0.1)
#最佳拟合直线
y = (-wei[0]-wei[1]*x)/wei[2]
ax.plot(x,y)
plt.xlabel('X1'); plt.ylabel('X2');
plt.show()
测试一下:
import logRegres
import numpy as np
dataArr,labelMat = logRegres.loadDataSet()
weights = logRegres.gradAscent(dataArr,labelMat)
logRegres.plotBestFit(np.array(weights))
这是梯度上升算法迭代500次的结果:得到一条Logistic回归最佳拟合直线
###随机梯度上升算法:
将以下代码写入logRegres.py文件中
def stocGradAscent0(dataMatrix, classLabels):
m,n = np.shape(dataMatrix)
alpha = 0.01
weights = np.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
测试一下:
dataArr,labelMat = logRegres.loadDataSet()
weight = logRegres.stocGradAscent0(np.array(dataArr),labelMat)
logRegres.plotBestFit(weight)
结果:
###改进的随机梯度上升算法:
将以下代码写入logRegres.py文件中
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = np.shape(dataMatrix)
weights = np.ones(n)
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
# alpha 每次迭代时需要调整
alpha = 4/(1.0 + j + i)+ 0.01
# 随机选取更新
randIndex = int(np.random.uniform(0, len(dataIndex)))
h = sigmoid(sum(dataMatrix[randIndex] * weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights
通过避免alpha参数的严格下降.来调整收敛的速度
测试一下:
weights = logRegres.stocGradAscent1(np.array(dataArr), labelMat)
logRegres.plotBestFit(weights)
结果:
我们可以看到,这个只遍历20次的与遍历500次的结果很接近了,说明优化是有效的
而且我们还可以通过修改迭代次数来获取更加精确的结果:
weights = logRegres.stocGradAscent1(np.array(dataArr), labelMat, 500)
logRegres.plotBestFit(weights)
结果:
##五、从疝气病症预测病马的死亡率
现在我们有horseColicTest.txt与horseColicTraining.txt两个文件,这两个文件已经经过预处理,但是数据集中是有30%缺失的,那么我们如何处理数据中的缺失值呢?
-使用可用特征的均值来填补缺失值
-使用特殊值来填补缺失值
-忽略有缺失值的样本
-使用相似样本的均值填补缺失值
-使用另外的机器学习算法预测缺失值
在本例中,我们将缺失值用0代替,因为sigmoid(0) = 0.5,这个结果对预测不具有倾向性,不会改变误差
###使用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.txt')
frTest = open('horseColicTest.txt')
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]))
trainWeights = stocGradAscent1(np.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(np.array(lineArr), trainWeights)) != int(currLine[21]):
errorCount += 1
errorRate = (float(errorCount)/numTestVec)
print("the error rate 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)))
测试一下:
logRegres.multiTest()
结果:
在经过一系列调参之后:
得到最优的结果是