用Logistic回归来预测患有疝病的马的存活问题。这里的数据包括368个样本和28个特征。疝病是描述马肠胃痛的术语,这种病并不一定源自马的肠胃问题。
该数据集中包含了医院检测马疝病的一些指标,有些指标比较主观,有的指标难以测量,例如马的疼痛级别。
除了部分指标主观和难以测量外,该数据还存在一个问题,那就是数据集中有30%的值是缺失的。下面将首先处理数据集中的数据缺失问题,然后再利用Logistic回归和随机梯度上升算法来预测马的生死。
准备数据:处理数据中的缺失值
数据中的缺失值是个非常棘手的问题:假设有100个样本和20个特征,这些数据都是数据收集回来的。若机器上的某个传感器导致一个特征无效,有以下方法可以解决这个问题:
1、使用可用特征的均值来填补缺失值;
2、使用特殊值来填充缺失值,如-1;
3、忽略有缺失值的样本;
4、使用相似样本的均值来添补缺失值;
5、使用另外的机器学习算法来预测缺失值。
现在,我们对数据集进行预处理,使其可以顺利地使用分类算法。在预处理阶段需要做两件事:
1、所有的缺失值必须用一个实数值来替代,因为我们使用的NumPy数据类型不允许包含缺失值。这里选择实数0来替换所有缺失值,恰好能使用Logistic回归,这样做的直觉在于,我们需要的事一个在更新时不会影响系数的值。回归系数的更新公式:
weights=weights+alpha*error*dataMatrix[ranIndex]
如果dataMatrix的某特征对应值为0,那么该特征的系数将不做更新,即:
weights=weights
另外,由于sigmoid(0)=0.5,即它对结果的预测不具有任何倾向性,因此上述做法也不会对误差项造成任何影响,基于上述原因,将缺失值用0代替既可以保留现有数据,也不需要对优化算法进行修改。此外,该数据集中的特征值一般不为0,因此在某种意义上来说它也满足“特殊值”这个要求。
2、如果在测试数据集中发现了一条数据的类别标签已经缺失,那么我们的简单做法是将该条数据丢弃。这是因为类别标签与特征不同,很难确定采用某个合适的值来替换。采用Logistic回归进行分类时这种做法是合理的,而如果采用类似kNN的方法就可能不太可行了。
测试算法:用Logistic回归进行分类
数据预览:
使用Logistic回归方法进行分类并不需要做很多工作,所需做的只是把测试集上每个特征向量乘以最优化方法得来的回归系数,再将该乘积结果求和,最后输入到Sigmoid函数中即可。如果对应的sigmoid值大于0.5就预测类别标签为1,否则为0。
实际代码:
def classifyVector(inX,weights):
prod=sigmoid(sum(inX*weights))
if prod>0.5:
return 1
else:
return 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,500)
errorCount=0
numTestVec=0.0
for line in frTest.readlines():
numTestVec=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=errorCount+1
errorRate=(float(errorCount)/numTestVec)
print('错误率:',errorRate)
return errorRate
def multiTest():
numTests=10
errorSum=0.0
for k in range(numTests):
errorSum=errorSum+colicTest()
print('运行次数,平均错误率',(numTests,errorSum/float(numTests)))
上述代码中,第一个函数是classifyVector(),它以回归系数和特征向量作为输入参数来计算对应的Sigmoid值,如果Sigmoid大于0.5函数返回1,否则返回0。
第二个函数colicTest()用于打开测试集和训练集,并对数据进行格式化处理的函数。该函数首先导入训练集,数据最后一列是类别标签:“扔存货”、“已经死亡”、“已经安乐死”。为了方便,将“已经死亡”和“已经安乐死”合并成“未存活”标签。输入导入后,可以用函数stocGradAscent1()来计算回归系数向量。这里可以自由设定迭代的次数。整体来看,colicTest()具有完全独立的功能,多次运行得到的结果可能稍有不同,这是因为其中有随机的成分在里面。
最后一个函数是multiTest(),功能是调用colicTest()10次并求结果的平均值: