使用Logistic迴歸預測病馬的死亡率
1. 問題描述
疝病是描述馬胃腸痛的術語,然而,這種病不一定源自馬的腸胃問題,其他問題也可能引發馬疝病。由於馬的身體指標測量引數十分多,同時對於預測結果僅需做出病馬是否死亡這一二分的判斷,Logistic迴歸在這一點上就十分合適。
2. 資料準備
對於資料集中的缺失值使用0來替代。因為sigmoid(0) = 0.5,對預測結果不具有侵向性,同時迭代函式weights = weights + alpha * error * dataMatrix[randIndex]在dataMatrix為0時不會做出更新。
預處理後的資料分為測試資料horseColicTest.txt和訓練資料horseColicTraining.txt
3. 模型原理
3.1.Sigmoid函式
,在較大座標尺度下近似與單位階躍函式,同時:
故Sigmoid函式具有很好的二分特性。
3.2.最佳迴歸係數確定
使用梯度上升法確定最佳迴歸係數。記梯度為▽,則函式f(x, y)的梯度由下式表示:
這個梯度意味著要沿x的方向移動,沿y的方向移動。其中,函式f(x, y)必須要在待計算的點有定義並且可微。
梯度運算元總是指向函式值增長最快的方向。移動量的值稱為步長,記作α。梯度演算法迭代公式為:
由此可快速得到最佳迴歸係數。
3.3.資料預測
Sigmoid函式的輸入值z,由下面公式得出:
將z帶入sigmoid函式得到函式值,以0.5為分界得到該資料的預測分類。
4. 演算法實現
4.1.sigmoid函式
def sigmoid(inX):
if inX>=0:
return 1.0/(1+exp(-inX))
else:
return exp(inX)/(1+exp(inX))
4.2.梯度上升優化演算法
def gradAscent(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn)
labelMat = mat(classLabels).transpose()
m,n = shape(dataMatrix)
alpha = 0.001
maxCycles = 500
weights = ones((n,1))
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights)
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose()* error
return weights
4.3.隨機梯度上升
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = shape(dataMatrix)
weights = ones(n)
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001
randIndex = int(random.uniform(0,len(dataIndex)))
h = sigmoid(sum(dataMatrix[randIndex]*weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * float64(dataMatrix[randIndex])
del(dataIndex[randIndex])
return weights
4.4.資料預測
def classifyVector(inX, weights):
prob = sigmoid(sum(inX*weights))
if prob > 0.5: return 1.0
else: return 0.0
4.5.單次資料測試
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
4.6.統計求正確率
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. 測試方法及結果
首先,針對一資料集進行演算法測試,得到分類效果:
圖一 梯度上升法得到的劃分
圖二 隨機梯度上升得到的劃分
可以看出,隨梯度上升得到的劃分與直接計算得到的劃分結果基本相同,但隨機梯度上升計算量更小。
對病馬資料集進行訓練測試,使用隨機梯度上升法做10次預測並統計平均正確率:
增加迭代次數得到結果:
6. 總結
Logistic迴歸是根據現有的資料對分類邊界線建立迴歸公式,並以此分類。其在最佳迴歸引數尋求中使用最優化的相關演算法並得出滿意結果。Logistic迴歸適用於數值型和標稱型資料,其計算代價不高,易於理解和實現,但容易出現欠擬合,分類精度可能不高。