本节将使用logistic回归来预测患有病的马的存活问题。数据集包括368个样本和28特征。
数据集中有部分指标是主观的难以测量,数据集中有30%是缺失的。下面我们将介绍如何处理数据集中的数据缺失问题,然后再利用logistic回归和随机梯度上升法来预测病马的生死。
1.准备数据:处理数据中的缺失值
数据采集过程中若某个传感器损坏导致一个特征无效该怎么办?所以我们必须采取一些方法来解决这个问题。
下面给出一些可选的做法:
现在对数据集做预处理,使其可以顺利地使用分类算法。在预处理阶段,必须要做两件事:第一,所有的缺失值必须使用一个实数值来替换,因为我们的Numpy数据类型不允许包含缺失值。这里选择实数0来替换所有的缺失值,恰好能用于Logistic回归。这样做的直觉在于我们需要一个在更新时不会影响系数的值。回归系数的更新公式如下:
如果dataMatrix的某特征对应值为0,那么该特征对应的系数将不更新。
另外由于sigmoid(0)=0.5,即它对结果的预测不具有任何的倾向性,因此上述做法也不会对误差造成任何影响。基于上述原因,将缺失值用0代替既可以保留现有的数据,也不需要对优化算法进行修改。此外,该数据集中的特征值一般不取0,因此在某种意义上说他也满足“特殊值”这个要求。
预处理中的第二件事是,如果在测试数据集中发现了一条数据的类别标签标记为缺失,那么我们的简单做法是将该数据丢弃。这是因为数据标签与特征不同,很难确定采用某个合适的值来代替。采用logistic回归进行分类时这种做法是合理的,而如果采用类似KNN的方法就不太可行。
采用上述方法处理完数据集之后,现在就有一个干净的数据集来进行优化算法了。
2.测试算法:用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(array(trainingSet), trainingLabels, 1000)
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), 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)))
数据导入后就可以计算梯度再估计分类了。整体来看colicTest()具有完全独立的功能,多次运行得到的结果可能稍有不同,我们最后一个函数就是求10个结果然后取平均。
运行效果如下所示:
可以看到最后错误率在32%左右,考虑到数据样本缺失在30%左右,所以这个结果还是可以接受的。
实际上更改步长和迭代次数,平均错误率可以降到20%左右,在第七章中我们会再使用这次数据集。