本節主要内容:
- 目的:尋找一個非線性函數Sigmoid的最佳拟合參數,求解過程由優化算法來完成。
- 最優化算法,最常用的是梯度上升算法,而梯度上升算法又可以簡化為随機梯度上升法,随機梯度上升法占用的計算資源更少,是一個線上算法,可以在新資料到來時完成參數的更新,而不需要重新讀取整個資料集進行批量處理。
- Logistic 回歸的一般過程
- 收集資料:采用任意方式收集資料
- 準備資料:由于需要進行距離計算,是以要求資料類型為數值型,另外,結構化資料格式更佳
- 分析資料:采用合适的方式對資料進行分析(比如可視化、資料的簡單處理等)
- 訓練算法:大部分時間用于訓練,訓練的目的是為了找到最佳的分類回歸系數
- 測試算法:一旦訓練完成,分類将會很快
2.使用算法:首先,将輸入資料轉化為結構化數值;然後,利用訓練好的回歸系數對輸入資料進行回歸計算,判定它們屬于哪個類别;最後,在輸出類别上做一些其他分析工作。
3.基于logistic回歸和sigmoid函數的分類
Sigmoid函數的集體計算公式:

Sigmoid函數的曲線圖:
圖1-1 兩種坐标尺度下的sigmoid函數圖。上圖為-8到8,曲線變化較為平滑;下圖坐标尺度較大-60到60,在(0,0.5)處看起來像階躍函數
為了實作logistic回歸分類器,可以在每個特征上乘以一個回歸系數,然後把所有的結果值相加,帶入到sigmoid函數中,進而得到0-1之間的數值。任意大于0.5的數值被分入1類,小于0.5的被分入0類。
4. 基于最優化方法的最佳回歸系數确定
Sigmoid函數的輸入記為z,由下面公式得出:
根據向量的寫法,上述公式寫成
,其中,x是分類器的輸入資料,向量w就是我們要找的最佳參數(系數),為了尋找最優化w值,還需要用到最優化理論。
4.1 梯度上升法
梯度上升法思想:要找到某個函數的最大值,最好的方法是沿着該函數的梯度方向尋找。函數f(x,y)的梯度由下式表示:
這個梯度意味着沿x方向移動
,沿着y的方向移動
在梯度上升算法中,梯度算子總是向函數值增長最快的方向,梯度是指最佳的移動方向,而移動量的大小稱為步長,記作
,用向量表示,梯度上升算法的疊代公式如下:
是指未更新的參數,
是指更新後參數
4.2 梯度下降法
梯度下降法用來計算函數的最小值,在梯度下降算法中,梯度算子總是向函數值增長最慢的方向。
梯度下降法用來計算函數的最小值,在梯度下降算法中,梯度算子總是向函數值增長最慢的方向。
5. 訓練算法:使用梯度上升算法找到最佳參數
給出一個簡單的資料集,利用logistic進行回歸分類:
圖1-2 一個簡單那資料集,二分類問題,綠色和紅色點分别為一類
圖1-2有100個樣本點,每個點包含兩個數值型特征:X1和X2,下面采用梯度上升法找到logistic回歸器在此資料及上的最佳回歸系數。
梯度上升法的僞代碼:
- 每個回歸系數初始化為1
- 重複n次:
- 計算整個資料集的梯度
- 使用 更新回歸系數的向量
機器學習實戰(logistic回歸)
- 傳回回歸系數
代碼實作:
from numpy import *
import matplotlib.pyplot as plt
def loadDataSet():
dataMat = []; labelMat = []
fr = open('testSet.txt') ##打開文本
for line in fr.readlines(): ##逐行讀取,每行前兩個值為X1和X2,第三個值是資料對應的标簽,将X0的值設定為1
lineArr = line.strip().split()
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(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn) #原始資料轉化為矩陣
labelMat = mat(classLabels).transpose() #标簽資料轉化為矩陣
m,n = shape(dataMatrix)
alpha = 0.001
maxCycles = 5000 ##疊代次數500
weights = ones((n,1)) ##初始化參數為1
temp= []
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights) #預測值
error = (labelMat - h) #向量
weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
return weights
疊代500次,得到回歸系數:
[[4.12414349]
[0.48007329]
[-0.6168482]]
畫出決策邊界:
上面已經解出一組回歸系數,它确定了不同類别資料之間的分割線。下面是畫出資料集和logistic回歸最佳拟合直線的函數:
##畫出資料集和logistic回歸最佳拟合直線
def plotBestFit(weights):
import matplotlib.pyplot as plt ##畫圖工具
dataMat,labelMat=loadDataSet()
dataArr = array(dataMat)
n = shape(dataArr)[0]
xcord1 = []; ycord1 = []
xcord2 = []; ycord2 = []
for i in range(n):
if int(labelMat[i])== 1: ##xcord1标簽值為1
xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
else:
xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2]) ##xcord2标簽值為0
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
ax.scatter(xcord2, ycord2, s=30, c='green')
x = arange(-3.0, 3.0, 0.1)
y = (-weights[0]-weights[1]*x)/weights[2]##0為兩類的分界處,故假定0=w0x0+w1x1+w2x2,x0=1
y = y.transpose()
ax.plot(x, y)
plt.xlabel('X1'); plt.ylabel('X2')
plt.show()
輸出結果:
圖1-3 梯度上升算法字500次疊代後得到的logistic回歸最佳拟合直線
這個分類結果從圖上看之分錯了2到4個點。盡管資料集很小,但是卻需要大量的計算(300次乘法),接下來對算法進行稍微改進。
6. 訓練算法:改進的随機梯度上升
梯度上升法在每次更新回歸系數時,都需要周遊整個資料集,該方法在處理100個左右的資料集尚可,但如果有數十億樣本和成千上萬的特征,那麼該方法的計算複雜度就太高了。一種改進方法:一次僅用一個樣本點來更新回歸系數,該方法稱為随機梯度上升算法。由于可以在新樣本到來時進行增量式更新,吟哦人随機梯度上升算法是一個線上學子算法。與線上學習相對應,一次處理所有資料稱為“批處理”。
改進的随機梯度上升算法:1.步長(學習率)在每次疊代的時候都會減小(不會減小到0),能夠緩解資料的波動或高頻波動。2. 通過随機選取樣本來更新回歸系數,每次随機從清單中選出一個值,然後從清單中删除該值(再進行下一次疊代)。
随機梯度上升算法僞代碼
- 每個回歸系數初始化為1
- 對資料中每個樣本:
- 計算該樣本的梯度
- 使用 更新回歸系數的向量
機器學習實戰(logistic回歸)
- 傳回回歸系數
實作代碼
##改進的随機梯度上升算法
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 ##數值型,float64
weights = weights + alpha * error *array(dataMatrix[randIndex]) ##參數更新
del(list(dataIndex)[randIndex]) ##删除該值進行下一次疊代
return weights
輸出結果:
這次僅對資料做了150次的周遊,而之前的方法是做了500次的周遊。該分割線和gradAscent()差不多的效果,但是作用計算量更少。
完整代碼:
from numpy import *
import matplotlib.pyplot as plt
def loadDataSet():
dataMat = []; labelMat = []
fr = open('testSet.txt') ##打開文本
for line in fr.readlines(): ##逐行讀取,每行前兩個值為X1和X2,第三個值是資料對應的标簽,将X0的值設定為1
lineArr = line.strip().split()
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(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn) #原始資料轉化為矩陣
labelMat = mat(classLabels).transpose() #标簽資料轉化為矩陣
m,n = shape(dataMatrix)
alpha = 0.001
maxCycles = 500 ##疊代次數500
weights = ones((n,1)) ##初始化參數為1
temp= []
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights) #預測值
error = (labelMat - h) #向量
weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
return weights
##畫出資料集和logistic回歸最佳拟合直線
def plotBestFit(weights):
import matplotlib.pyplot as plt ##畫圖工具
dataMat,labelMat=loadDataSet()
dataArr = array(dataMat)
n = shape(dataArr)[0]
xcord1 = []; ycord1 = []
xcord2 = []; ycord2 = []
for i in range(n):
if int(labelMat[i])== 1: ##xcord1标簽值為1
xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
else:
xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2]) ##xcord2标簽值為0
fig = plt.figure()
ax = fig.add_subplot(111)
ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')
ax.scatter(xcord2, ycord2, s=30, c='green')
x = arange(-3.0, 3.0, 0.1)
y = (-weights[0]-weights[1]*x)/weights[2]##0為兩類的分界處,故假定0=w0x0+w1x1+w2x2,x0=1
y = y.transpose()
ax.plot(x, y)
plt.xlabel('X1'); plt.ylabel('X2')
plt.show()
##随機
def stocGradAscent0(dataMatrix, classLabels):
m,n = shape(dataMatrix)
alpha = 0.01
weights = ones(n) #initialize to all ones
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h ##數值
weights = weights + alpha * error * dataMatrix[i]
return weights
##改進的随機梯度上升算法
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 ##數值型,float64
weights = weights + alpha * error *array(dataMatrix[randIndex]) ##參數更新
del(list(dataIndex)[randIndex]) ##删除該值進行下一次疊代
return weights
if __name__=='__main__':
dataMat,labelMat = loadDataSet()
# weights = gradAscent(dataMat,labelMat) ##梯度下降算法回歸系數
weights1 = stocGradAscent1(dataMat,labelMat) ##改進随機梯度下降算法回歸系數
# plotBestFit(weights) ##畫出梯度下降算法在資料集上的拟合直線
plotBestFit(weights1) ##畫出改進随機梯度下降算法在資料集上的拟合直線
上面是具體的分類任務,下節涉及到的是使用随機梯度上升算法來解決病馬的生死生死預測問題