讀古今文學網 > 機器學習實戰 > 5.3 示例:從疝氣病症預測病馬的死亡率 >

5.3 示例:從疝氣病症預測病馬的死亡率

本節將使用Logistic回歸來預測患有疝病的馬的存活問題。這裡的數據1包含368個樣本和28個特徵。我並非育馬專家,從一些文獻中瞭解到,疝病是描述馬胃腸痛的術語。然而,這種病不一定源自馬的胃腸問題,其他問題也可能引發馬疝病。該數據集中包含了醫院檢測馬疝病的一些指標,有的指標比較主觀,有的指標難以測量,例如馬的疼痛級別。

1. 數據集來自2010年1月11日的UCI機器學習數據庫(http://archive.ics.uci.edu/ml/datasets/Horse+Colic)。該數據最早由加拿大安大略省圭爾夫大學計算機系的Mary McLeish和Matt Cecile收集。

示例:使用Logistic回歸估計馬疝病的死亡率

  1. 收集數據:給定數據文件。
  2. 準備數據:用Python解析文本文件並填充缺失值。
  3. 分析數據:可視化並觀察數據。
  4. 訓練算法:使用優化算法,找到最佳的係數。
  5. 測試算法:為了量化回歸的效果,需要觀察錯誤率。根據錯誤率決定是否回退到訓練階段,通過改變迭代的次數和步長等參數來得到更好的回歸係數。
  6. 使用算法:實現一個簡單的命令行程序來收集馬的症狀並輸出預測結果並非難事,這可以做為留給讀者的一道習題。

另外需要說明的是,除了部分指標主觀和難以測量之外,該數據集還存在一個問題,數據集中有30%的數據值是缺失的。下面將首先介紹如何處理數據集中的數據缺失問題,然後再利用Logistic回歸和隨機梯度上升算法來預測病馬的生死。

5.3.1 準備數據:處理數據中的缺失值

數據中的缺失值是個非常棘手的問題,有很多文獻都致力於解決這個問題。那麼,數據缺失究竟帶來了什麼問題?假設有100個樣本和20個特徵,這些數據都是機器收集回來的。若機器上的某個傳感器損壞導致一個特徵無效時該怎麼辦?此時是否要扔掉整個數據?這種情況下,另外19個特徵怎麼辦?它們是否還可用?答案是肯定的。因為有時候數據相當昂貴,扔掉和重新獲取都是不可取的,所以必須採用一些方法來解決這個問題。

下面給出了一些可選的做法:

  • 使用可用特徵的均值來填補缺失值;
  • 使用特殊值來填補缺失值,如-1;
  • 忽略有缺失值的樣本;
  • 使用相似樣本的均值添補缺失值;
  • 使用另外的機器學習算法預測缺失值。

現在,我們對下一節要用的數據集進行預處理,使其可以順利地使用分類算法。在預處理階段需要做兩件事:第一,所有的缺失值必須用一個實數值來替換,因為我們使用的NumPy數據類型不允許包含缺失值。這裡選擇實數0來替換所有缺失值,恰好能適用於Logistic回歸。原因在於,我們需要的是一個在更新時不會影響係數的值。回歸係數的更新公式如下:

weights = weights + alpha * error * dataMatrix[randIndex
  

如果dataMatrix的某特徵對應值為0,那麼該特徵的係數將不做更新,即:

weights = weights
  

另外,由於sigmoid(0)=0.5,即它對結果的預測不具有任何傾向性,因此上述做法也不會對誤差項造成任何影響。基於上述原因,將缺失值用0代替既可以保留現有數據,也不需要對優化算法進行修改。此外,該數據集中的特徵取值一般不為0,因此在某種意義上說它也滿足「特殊值」這個要求。

預處理中做的第二件事是,如果在測試數據集中發現了一條數據的類別標籤已經缺失,那麼我們的簡單做法是將該條數據丟棄。這是因為類別標籤與特徵不同,很難確定採用某個合適的值來替換。採用Logistic回歸進行分類時這種做法是合理的,而如果採用類似kNN的方法就可能不太可行。

原始的數據集經過預處理之後保存成兩個文件:horseColicTest.txthorseColicTraining.txt。如果想對原始數據和預處理後的數據做個比較,可以在http://archive.ics.uci.edu/ml/datasets/Horse+Colic瀏覽這些數據。

現在我們有一個「乾淨」可用的數據集和一個不錯的優化算法,下面將把這些部分融合在一起訓練出一個分類器,然後利用該分類器來預測病馬的生死問題。

5.3.2 測試算法:用Logistic回歸進行分類

本章前面幾節介紹了優化算法,但目前為止還沒有在分類上做任何實際嘗試。使用Logistic回歸方法進行分類並不需要做很多工作,所需做的只是把測試集上每個特徵向量乘以最優化方法得來的回歸係數,再將該乘積結果求和,最後輸入到Sigmoid函數中即可。如果對應的Sigmoid值大於0.5就預測類別標籤為1,否則為0。

下面看看實際運行效果,打開文本編輯器並將下列代碼添加到logRegres.py文件中。

程序清單5-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(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), 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))
  

程序清單5-5的第一個函數是classifyVector,它以回歸係數和特徵向量作為輸入來計算對應的Sigmoid值。如果Sigmoid值大於0.5函數返回1,否則返回0。

接下來的函數是colicTest,是用於打開測試集和訓練集,並對數據進行格式化處理的函數。該函數首先導入訓練集,同前面一樣,數據的最後一列仍然是類別標籤。數據最初有三個類別標籤,分別代表馬的三種情況:「仍存活」、「已經死亡」和「已經安樂死」。這裡為了方便,將「已經死亡」和「已經安樂死」合併成「未能存活」這個標籤 。數據導入之後,便可以使用函數stocGradAscent1來計算回歸係數向量。這裡可以自由設定迭代的次數,例如在訓練集上使用500次迭代,實驗結果表明這比默認迭代150次的效果更好。在係數計算完成之後,導入測試集並計算分類錯誤率。整體看來,colicTest具有完全獨立的功能,多次運行得到的結果可能稍有不同,這是因為其中有隨機的成分在裡面。如果在stocGradAscent1函數中回歸係數已經完全收斂,那麼結果才將是確定的。

最後一個函數是multiTest,其功能是調用函數colicTest10次並求結果的平均值。下面看一下實際的運行效果,在Python提示符下輸入:

>>> reload(logRegres)
<module \'logRegres\' from \'logRegres.py\'>
>>> logRegres.multiTest
the error rate of this test is: 0.358209
the error rate of this test is: 0.432836
the error rate of this test is: 0.373134
                          .
                          .
the error rate of this test is: 0.298507
the error rate of this test is: 0.313433
after 10 iterations the average error rate is: 0.353731
  

從上面的結果可以看到,10次迭代之後的平均錯誤率為35%。事實上,這個結果並不差,因為數據集有30%的數據已經缺失。當然,如果調整colicTest中的迭代次數和stochGradAscent1中的步長,平均錯誤率可以降到20%左右。第7章中我們還會再次使用到這個數據集。