最近一直在看機器學習相關的算法,今天學習logistic回歸,在對算法進行了簡單分析編程實現之后,通過實例進行驗證。
一 logistic概述
個人理解的回歸就是發現變量之間的關系,也就是求回歸系數,經常用回歸來預測目標值。回歸和分類同屬於監督學習,所不同的是回歸的目標變量必須是連續數值型。
今天要學習的logistic回歸的主要思想是根據現有的數據對分類邊界線建立回歸公式,以此進行分類。主要在流行病學中應用較多,比較常用的情形是探索某疾病的危險因素,根據危險因素預測某疾病發生的概率等等。logistic回歸的因變量可以是二分類的,也可以是多分類的,但是二分類的更為常用,也更加容易解釋,所以實際中最為常用的就是二分類的logistic回歸。
今天我們就二分類進行分析,我們在回歸分析中需要一個函數可以接受所有的輸入然后預測出類別,假定用0和1分別表示兩個類別,logistic函數曲線很像S型,故此我們可以聯系sigmoid函數:σ = 1/(1/(1+e-z))。為了實現logistic回歸分類器,我們可以在每個特征上乘以一個回歸系數,將所有的乘積相加,將和值代入sigmoid函數中,得到一個范圍為0-1之間的數,如果該數值大於0.5則被歸入1類,否則被歸為0類。
基於之前的分析,需要找到回歸系數,首先我們可以將sigmoid函數的輸入形式記為:z = w0x0 + w1x1 +...+wnxn,其中x為輸入數據,相應的w就是我們要求的系數,為了求得最佳系數,結合最優化理論,我們可以選取梯度上升法優化算法。梯度上升法的基本思想是:要找到函數的最大值,最好的方法是沿着該函數的梯度方向尋找。要想更進一步的了解這個方法,建議去看Andrew Ng的機器學習課程,記得在第二節主要講述的就是梯度下降法,與梯度上升所不同的是它求得的是函數的最小值,不過思想是一致的。
二 python實現
基於之前的分析,在本節我們對logistic回歸一步一步采用python編程實現,今天我用的是2.7版本的,代碼如下:
#coding:utf-8 from numpy import * import math import matplotlib.pyplot as plt #導入數據 def loadDataSet(): dataMat = [] labelMat = [] fr = open('testSet.txt') for line in fr.readlines(): lineArr = line.strip().split()#將文本中的每行中的字符一個個分開,變成list dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])]) labelMat.append(int(lineArr[2])) return dataMat,labelMat #定義sigmoid函數 def sigmoid(inX): return 1.0/(1+exp(-inX)) #梯度上升方法求出回歸系數 def gradAscent(data,label): dataMat = mat(data) labelMat = mat(label).transpose() m,n = shape(dataMat) alpha = 0.001 maxCycles = 500 weights = ones((n,1)) for item in range(maxCycles): h = sigmoid(dataMat * weights) error = (labelMat - h)#注意labelMat中的元素的數據類型應為int weights = weights + alpha * dataMat.transpose() * error return weights ''' #測試 data,label = loadDataSet() print gradAscent(data,label) ''' ##求出回歸系數之后,就確定了不同數據類別之間的分隔線,為了便於理解,可以畫出那條線 def plotBestFit(weights): dataMat,labelMat = loadDataSet() dataArr = array(dataMat) n = shape(dataArr)[0] xcode1 = [] ycode1 = [] xcode2 = [] ycode2 = [] for i in range(n): if int(labelMat[i]) == 1: xcode1.append(dataArr[i,1]) ycode1.append(dataArr[i,2]) else: xcode2.append(dataArr[i,1]) ycode2.append(dataArr[i,2]) fig = plt.figure() ax = fig.add_subplot(111) ax.scatter(xcode1,ycode1,s = 30,c = 'red',marker = 's') ax.scatter(xcode2,ycode2,s = 30,c = 'green') x = arange(-3.0,3.0,0.1) y = (-weights[0] - weights[1] * x) / weights[2] ax.plot(x,y) plt.xlabel('x1') plt.ylabel('y1') plt.show() ''' #測試 data,label = loadDataSet() weights = gradAscent(data,label) plotBestFit(weights.getA()) ''' ##改進的梯度上升法 def stocGradAscent1(dataMatrix, classLabels, numIter=150): m,n = shape(dataMatrix) weights = ones(n) #initialize to all ones for j in range(numIter): dataIndex = 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 * dataMatrix[randIndex] del(dataIndex[randIndex]) return weights ''' #測試 data,label = loadDataSet() weights = stocGradAscent1(array(data),label) plotBestFit(weights) '''
三 實例分析
基於之前的分析,本節采用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 "錯誤率是:",errorRate return errorRate def multiTest(): numTests = 10; errorSum=0.0 for k in range(numTests): errorSum += colicTest() print "平均錯誤率是",(numTests, errorSum/float(numTests)) multiTest()
最后可以看出錯誤率在35%左右,通過調節步長還是可以進一步減小錯誤率。
Logistic回歸的目的是尋找到一個非線性sigmoid函數的最佳擬合參數,可以采用梯度上升法優化,而在這個過程中,為了減少時間復雜度,又可以使用隨機梯度上升法來簡化梯度上升法。