写程序学ML:Logistic回归算法原理及实现(三)

来源:互联网 发布:37轩辕剑进阶数据 编辑:程序博客网 时间:2024/05/12 03:10

2.2   利用Logistic算法预测病马死亡率

由于采集数据是诸多原因,采集的数据有可能不完整。但有时候数据相当昂贵,扔掉和重新获取都是不可取的,所以必须采用一些方法来解决这个问题。

处理数据中缺失值的做法

1>    使用可用特征的均值来填补缺失值;

2>    使用特殊值来填补缺失值;

3>    忽略有缺失值的样本;

4>    使用相似样本的均值添补缺失值;

5>    使用另外的机器学习算法预测缺失值;

对于采集到的数据进行预处理,可以使其顺利地使用分类算法。在预处理阶段做两件事:

第一,所有的缺失值必须用一个实数值来替换,因为我们使用的NumPy数据类型不允许包含缺失值。这里选择实数0来替换所有缺失值,恰好能适用于Logistic回归。这样做的直觉在于,我们需要的是一个在更新时不会影响系数的值。回归系数的更新公式如下:

weights =weights + alpha * error * dataMatrix[randIndex]

如果dataMatrix的某特征对应值为0,那么该特征的系数将不做更新,即:

weights =weights

另外,由于sigmoid(0) = 0.5,即它对结果的预测不具有任何倾向性,因此上述做法也不会对误差造成任何影响。基于上述原因,将缺失值用0代替既可以保留现有数据,也不需要对优化算法进行修改。此外,该数据集中的特征取值一般不为0,因此在某种意义上说它也满足“特征值”这个要求。

第二件事:如果在测试数据集中发现了一条数据的类别标签已经缺失,那么我们的简单做法是将该条数据丢弃。这是因为类别标签与特征不同,很难确定采用某个合适的值来替换。采用Logistic回归进行分类时这种做法是合理的,而如果采用类似kNN的方法就可能不太可行。

使用Logistic回归方法进行分类并不需要做很多工作,所需做的只是把测试集上每个特征向量乘以最优化方法得来的回归系数,再将该乘积结果求和,最后输入到sigmoid函数中即可。如果对应sigmoid值大于0.5就预测类别标签为1,否则为0。

对于病马死亡率的判断,可以使用前面实现的Logistic回归算法。

首先从训练样本文件中读取训练样本,解析出特征值和分类情况。

调用改进的随机梯度上升算法函数stocGradAscent1()产生回归系数。

然后从测试样本文件中读取测试样本,解析出特征值和分类情况。

调用分类函数classifyVector()对测试样本进行分类,判断该分类正确情况。

最后返回分类错误率。程序中对测试样本进行了10次测试,求得了平均错误率。

程序的具体实现如下:

#使用改进的随机梯度上升算法,通过训练样本产生回归系数;#利用回归系数对测试样本进行分类,统计分类错误率def colicTest():    frTrain = open('horseColicTraining.txt') #打开训练样本集    frTest = open('horseColicTest.txt') #打开测试样本集    trainingSet = [] #存储所有样本的特征值的列表变量    trainingLabels = [] #存储所有样本分类信息的列表变量    #每个样本中有21个特征值,存储在变量trainingSet中;每个样本的分类信息存储在变量trainingLabels中    for line in frTrain.readlines(): #从训练样本文件中逐个取出样本        currLine = line.strip().split('\t') #去掉行首行末的空格,并用空格分隔,即将22个数值取出存到变量中        lineArr = []        for i in range(21): #将21个特征值从列表变量currLine中读取出来,储存到列表变量lineArr中            lineArr.append(float(currLine[i]))        trainingSet.append(lineArr) #将当前样本20个特征值添加到列表trainingSet中        trainingLabels.append(float(currLine[21])) #将当前样本分类信息添加到列表trainingLabels中    #调用改进的随机梯度上升算法对训练样本进行500次迭代训练,产生回归系数    trainWeights = Logistic.stocGradAscent1(array(trainingSet), trainingLabels, 500)    errorCount = 0    numTestVec = 0    #使用获取的回归系数,对测试样本进行分类,判断分类正确情况    for line in frTest.readlines():        numTestVec += 1.0 #统计测试样本个数        currLine = line.strip().split('\t') #去掉行首行末的空格,并用空格分隔,即将22个数值取出存到变量中        lineArr = []        for i in range(21): #将21个特征值从列表变量currLine中读取出来,储存到列表变量lineArr中            lineArr.append(float(currLine[i]))        #判断当前测试样本的分类情况是否与真实分类一致;如果不一致,错误次数加1        if int(Logistic.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 = 1.0    for k in range(numTests): #统计10次测试的错误率,并累加        errorSum += colicTest()    print "after %d iterations the average error rate is: %f" % \    (numTests, errorSum / float(numTests)) #打印出10次平均错误率

3、小结

Logistic回归的目的是寻找一个非线性函数sigmoid的最佳拟合参数,求解过程可以由最优化算法来完成。在最优化算法中,最常用的就是梯度上升算法,而梯度上升算法又可以简化为随机梯度上升算法。

随机梯度上升算法与梯度上升算法的效果相当,但占用更少的计算资源。此外,随机梯度上升是一个在线算法,它可以在新数据到来时就完成参数更新,而不需要更新读取整个数据集来进行批处理运算。

机器学习的一个重要问题是如何处理缺失数据。这个问题没有标准答案,取决于实际应用中的需求。现有一些解决方案,每种方案都各有优缺点。

本文中涉及的所有code可以访问如下目录获取:

https://github.com/stevewang0/MLInAction

(全文完)
阅读全文
0 0
原创粉丝点击