邏輯迴歸也被稱爲廣義線性迴歸模型,它與線性迴歸模型的形式基本相同,最大的區別是它們的因變量不同,如果是連續的,就是多重線性迴歸,如果是二項分佈,就是 Logistic迴歸。
Logistic迴歸雖然名字裏帶“迴歸”,但它實際上是一種分類方法,主要用於二分類問題。邏輯迴歸就是這樣的一個過程:面對一個迴歸或者分類問題,建立相應的函數,然後通過優化方法迭代求解出最優的模型參數,然後測試驗證這個求解的模型的好壞。
它的優點有:
速度快,適合二分類問題;
簡單、易於理解,可以直接看到各個特徵的權重;
能容易地更新模型吸收新的數據。
它的缺點有:
對數據和場景的適應能力有侷限性,不如決策樹算法適應性強。
常規步驟:尋找預測函數,構造損失函數(J),使損失函數J最小並求得迴歸係數()
構造預測函數
二分類問題與自變量之間的關係圖形是往往是一個S型曲線。例:採用 sigmoid函數實現:
對於線性邊界的形式如下:
最佳參數:
構造預測函數:
sigmoid函數的輸出是介於(0,1)之間的,之間值是0.5。因爲hθ(x)輸出是介於(0,1)之間,也就表明了數據屬於某一類別的概率。例如,hθ(x)<0.5則說明當前數據屬於A類;hθ(x)>0.5則說明當前數據屬於B類。所以可以將sigmoid函數看成樣本數據的概率密度函數。
構造損失函數
最大似然法是邏輯迴歸所採用的參數估計方法,其原理是找到這樣一個參數,可以讓樣本數據所包含的觀察值被觀察到的可能性最大。最大似然估計的優點是大樣本數據中的參數的估計穩定,偏差小,估計方差小。
採用概率論中的極大似然估計的方法求解損失函數:
首先得到概率函數:
因爲樣本獨立,所以對它們的聯合分佈可以表示爲各個邊際的分佈的乘積,取似然函數:
取對數似然函數:
最大似然估計就是要事 l(θ)取得最大值時的 θ,這裏可以用梯度上升法求解,得到最佳參數:
梯度下降法求解最小值
θ更新
θ的更新過程可以寫成爲:
向量化:把訓練數據約定爲矩陣的形式,x的每一行就表示一條數據,每一列爲不同的特徵
正則化:過擬合就是過分擬合了訓練數據,使得模型的複雜度提高,泛化能力降低
下列 左圖爲欠擬合,中圖爲合社的擬合,右圖爲過擬合
使用正則化可以解決過擬合的問題,正則化是結構風險最小化策略的實現,是在經驗風險上加一個正則化項或懲罰項。正則化項一般是模型複雜度的單調遞增函數,模型越複雜,正則化項就越大。
正則化可以採取不同的形式,在迴歸問題上取平方損失,就是參數的L2範數,也可以取L1範數。取平方損失,模型的損失函數爲:
正則化後的梯度下降算法θ的更新變爲:
數據操作
from numpy import *
import pandas as pd
from pandas import DataFrame
filename='./data.txt' #文件目錄
def loadDataSet(): #讀取數據(這裏只有兩個特徵)
df=pd.read_csv(filename)
dataMat = []
labelMat = []
fr = open(filename)
for line in fr.readlines():
lineArr = line.strip().split()
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])]) #前面的1,表示方程的常量。比如兩個特徵X1,X2,共需要三個參數,W1+W2*X1+W3*X2
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
def sigmoid(inX): #sigmoid函數
return 1.0/(1+exp(-inX))
def GradAscent(dataMat, labelMat): #改進版隨機梯度上升,在每次迭代中隨機選擇樣本來更新權重,並且隨迭代次數增加,權重變化越小。
dataMatrix=mat(dataMat)
classLabels=labelMat
m,n=shape(dataMatrix)
weights=ones((n,1))
maxCycles=500
for j in range(maxCycles): #迭代
dataIndex=[i for i in range(m)]
for i in range(m): #隨機遍歷每一行
alpha=4/(1+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].transpose()
del(dataIndex[randIndex]) #去除已經抽取的樣本
return weights
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.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('X1')
plt.ylabel('X2')
plt.show()
plt.savefig('logExample.png', format='png')
def main():
datamat,labelmat=loadDataSet()
weights= GradAscent(datamat, labelmat).getA()
plotBestFit(weights)
if __name__=='__main__':
main()