機器學習筆記(6)-邏輯迴歸與最大熵模型
Logistic迴歸
Logistic 迴歸雖然名字叫回歸,但是它是用來做分類的。其主要思想是: 根據現有資料對分類邊界線建立迴歸公式,以此進行分類。假設現在有一些資料點,我們用一條直線對這些點進行擬合(這條直線稱為最佳擬合直線),這個擬合的過程就叫做迴歸。
Sigmoid 函式
Sigmoid 函式具體的計算公式
def sigmoid(inX):
return 1.0/(1+exp(-inX))
為了實現 Logistic 迴歸分類器,我們可以在每個特徵上都乘以一個迴歸係數(如下公式所示),然後把所有結果值相加,將這個總和代入 Sigmoid 函式中,進而得到一個範圍在 0~1 之間的數值。任何大於 0.5 的資料被分入 1 類,小於 0.5 即被歸入 0 類。所以, Logistic 迴歸也可以被看成是一種概率估計。
Sigmoid 函式的輸入記為 z ,由下面公式得到:
邏輯斯蒂迴歸模型
1. 二項邏輯斯蒂迴歸模型
二項邏輯斯蒂迴歸模型是如下的條件概率分佈:
意義:在邏輯斯蒂迴歸模型中,輸出Y=1的對數機率是輸入x的線性函式。或者說,輸出Y=1的對數機率是由屬於x的線性函式表示的模型,即邏輯斯蒂迴歸模型。
感知機只通過決策函式(w⋅x)的符號來判斷屬於哪一類。邏輯斯蒂迴歸需要再進一步,它要找到分類概率P(Y=1)與輸入向量x的直接關係,再通過比較概率值來判斷類別。
令決策函式(w⋅x)輸出值等於概率值比值取對數,即:
邏輯斯蒂迴歸模型的定義式P(Y=1|x)中可以將線性函式w⋅x轉換為概率,這時,線性函式的值越接近正無窮,概率值就越接近1;線性函式的值越接近負無窮,概率值就接近0.
2. 模型引數估計
應用極大似然法進行引數估計,從而獲得邏輯斯蒂迴歸模型。
上式連乘符號內的兩項中,每個樣本都只會取到兩項中的某一項。若該樣本的實際標籤yi=1,取樣本計算為1的概率值π(xi);若該樣本的實際標籤yi=0,取樣本計算的為0的概率值1−π(xi)。
3對數似然函式為:
對上式中的L(w)求極大值,得到w的估計值。
問題轉化成以對數似然函式為目標函式的無約束最優化問題,通常採用梯度下降法以及擬牛頓法求解w。
假設w的極大估計值是wˆ,那麼學到的邏輯斯蒂迴歸模型為:
利用梯度上升找到最佳引數
4. 交叉熵損失函式的求導:邏輯迴歸的另一種理解是以交叉熵作為損失函式的目標最優化。交叉熵損失函式可以從上文最大似然推匯出來。 交叉熵損失函式為:
則可以得到目標函式為:
計算J(θ)對第j個引數分量θj求偏導:
def gradAscent(dataMatIn, classLabels):
'''正常的梯度上升法
:param dataMatIn: ataMatIn 是一個2維NumPy陣列,每列分別代表每個不同的特徵,每行則代表每個訓練樣本。
:param classLabels: classLabels 是類別標籤,它是一個 1*100 的行向量。為了便於矩陣計算,需要將該行向量轉換為列向量,做法是將原向量轉置,再將它賦值給labelMat。
:return array(weights)-得到的最佳迴歸係數
'''
dataMatrix = mat(dataMatIn)
labelMat = mat(classLabels).transpose() # 轉化為矩陣[[0,1,0,1,0,1.....]],並轉制[[0],[1],[0].....]
m,n = shape(dataMatrix)
alpha = 0.001 # alpha代表向目標移動的步長
maxCycles = 500 # 迭代次數
weights = ones((n,1)) # 生成一個長度和特徵數相同的矩陣
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights) # mxn+nx1->mx1
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose() * error # 矩陣乘法,最後得到迴歸係數
return array(weights)
梯度上升優化演算法在每次更新資料集時都需要遍歷整個資料集,計算複雜都較高;改進方法為隨機梯度上升:一次只用一個樣本點來更新迴歸係數。
def stocGradAscent0(dataMatrix, classLabels):
m,n = shape(dataMatrix); alpha = 0.01
weights = ones(n)
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
print weights, "*"*10 , dataMatrix[i], "*"*10 , error
weights = weights + alpha * error * dataMatrix[i]
return weights
改進的隨機梯度上升演算法:1,alpha在每次迭代的時候都會調整;2,通過隨機選取樣本來更新迴歸係數;
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
'''
:param dataMatrix: 輸入資料的資料特徵(除去最後一列資料)
:param classLabels: 輸入資料的類別標籤(最後一列資料)
:param numIter: 迭代次數
:return: weights -- 得到的最佳迴歸係數
'''
m,n = shape(dataMatrix)
weights = ones(n) # 建立與列數相同的矩陣的係數矩陣,所有的元素都是1
for j in range(numIter): # 隨機梯度, 迴圈150,觀察是否收斂
dataIndex = range(m)
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001 # alpha 會隨著迭代不斷減小,但永遠不會減小到0,因為後邊還有一個常數項0.0001
randIndex = int(random.uniform(0,len(dataIndex))) # random.uniform(x, y) 方法將隨機生成下一個實數,它在[x,y]範圍內,x是這個範圍內的最小值,y是這個範圍內的最大值。
h = sigmoid(sum(dataMatrix[randIndex]*weights)) # sum(dataMatrix[i]*weights)為了求 f(x)的值, f(x)=a1*x1+b2*x2+..+nn*xn
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights
根據權重用logistic畫最佳擬合直線
def plotBestFit(dataArr, labelMat, weights):
'''將我們得到的資料視覺化展示出來
:param dataArr: 樣本資料的特徵
:param labelMat: 樣本資料的類別標籤,即目標變數
:param weights: 迴歸係數
:return:
'''
n = shape(dataArr)[0]
xcord1 = []; ycord1 = []
xcord2 = []; ycord2 = []
for i in range(n):
if int(labelMat[i])== 1:
xcord1.append(dataArr[i,1]); ycord1.append(dataArr[i,2])
else:
xcord2.append(dataArr[i,1]); ycord2.append(dataArr[i,2])
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]
ax.plot(x, y)
plt.xlabel('X'); plt.ylabel('Y')
plt.show()