邏輯回歸--簡介
邏輯回歸(Logistic Regression)就是這樣的一個過程:面對一個回歸或者分類問題,建立代價函數,然后通過優化方法迭代求解出最優的模型參數,然后測試驗證我們這個求解的模型的好壞。
Logistic回歸雖然名字里帶“回歸”,但是它實際上是一種分類方法,主要用於兩分類問題(即輸出只有兩種,分別代表兩個類別)。
回歸模型中,y是一個定性變量,比如y=0或1,logistic方法主要應用於研究某些事件發生的概率。
邏輯回歸--優缺點
優點:
1、速度快,適合二分類問題 ;
2、簡單易於理解,直接看到各個特征的權重 ;
3、能容易地更新模型吸收新的數據 ;
缺點:
1、對數據的場景的適應能力有局限性,不如決策樹算法適應性強;
邏輯回歸--用途
用途:
1、尋找危險因素:尋找某一疾病的危險因素等;
2、預測:根據模型,預測在不同的自變量情況下,發生某病或某種情況的概率有多大;
3、判別:實際上跟預測有些類似,也是根據模型,判斷某人屬於某病或屬於某種情況的概率有多大,也就是看一下這個人有多大的可能性是屬於某病
邏輯回歸--原理
Logistic Regression和Linear Regression的原理是相似的,按照我自己的理解,可以簡單的描述為這樣的過程:
(1)找一個合適的預測函數(Andrew Ng的公開課中稱為hypothesis),一般表示為h函數,該函數就是我們需要找的分類函數,它用來預測輸入數據的判斷結果。這個過程時非常關鍵的,需要對數據有一定的了解或分析,知道或者猜測預測函數的“大概”形式,比如是線性函數還是非線性函數。
(2)構造一個Cost函數(損失函數),該函數表示預測的輸出(h)與訓練數據類別(y)之間的偏差,可以是二者之間的差(h-y)或者是其他的形式。綜合考慮所有訓練數據的“損失”,將Cost求和或者求平均,記為J(θ)函數,表示所有訓練數據預測值與實際類別的偏差。
(3)顯然,J(θ)函數的值越小表示預測函數越准確(即h函數越准確),所以這一步需要做的是找到J(θ)函數的最小值。找函數的最小值有不同的方法,Logistic Regression實現時有的是梯度下降法(Gradient Descent)。
邏輯回歸--具體過程
一、構造預測函數
Logistic回歸雖然名字里帶“回歸”,但是它實際上是一種分類方法,主要用於兩分類問題(即輸出只有兩種,分別代表兩個類別),所以利用了Logistic函數(或稱為Sigmoid函數),函數形式為:
Sigmoid 函數在有個很漂亮的“S”形,如下圖所示:
下面左圖是一個線性的決策邊界,右圖是非線性的決策邊界:
對於線性邊界的情況,邊界形式如下:
構造預測函數為:
函數的值有特殊的含義,它表示結果取1的概率,因此對於輸入x分類結果為類別1和類別0的概率分別為:
二、構造損失函數
Cost 函數和 J 函數如下,它們是基於最大似然估計推導得到的:
下面詳細說明推導的過程:
(1)式綜合起來可以寫成:
取似然函數為:
對數似然函數為:
最大似然估計就是求使取最大值時的θ,其實這里可以使用梯度上升法求解,求得的θ就是要求的最佳參數。但是,在Andrew Ng的課程中將 J(θ) 取為下式,即:
因為乘了一個負的系數-1/m,所以取 J(θ) 最小值時的θ為要求的最佳參數。
三、梯度下降法求的最小值
求J(θ)的最小值可以使用梯度下降法,根據梯度下降法可得θ的更新過程:
式中為α學習步長,下面來求偏導:
θ更新過程可以寫成:
邏輯回歸--實例
# -*- coding: utf-8 -*-
from numpy import *
import matplotlib.pyplot as plt
#從文件中加載數據:特征X,標簽label
def loadDataSet():
dataMatrix=[]
dataLabel=[]
#這里給出了python 中讀取文件的簡便方式
f=open('testSet.txt')
for line in f.readlines():
#print(line)
lineList=line.strip().split()
dataMatrix.append([1,float(lineList[0]),float(lineList[1])])
dataLabel.append(int(lineList[2]))
#for i in range(len(dataMatrix)):
# print(dataMatrix[i])
#print(dataLabel)
#print(mat(dataLabel).transpose())
matLabel=mat(dataLabel).transpose()
return dataMatrix,matLabel
#logistic回歸使用了sigmoid函數
def sigmoid(inX):
return 1/(1+exp(-inX))
#函數中涉及如何將list轉化成矩陣的操作:mat()
#同時還含有矩陣的轉置操作:transpose()
#還有list和array的shape函數
#在處理矩陣乘法時,要注意的便是維數是否對應
#graAscent函數實現了梯度上升法,隱含了復雜的數學推理
#梯度上升算法,每次參數迭代時都需要遍歷整個數據集
def graAscent(dataMatrix,matLabel):
m,n=shape(dataMatrix)
matMatrix=mat(dataMatrix)
w=ones((n,1))
alpha=0.001
num=500
for i in range(num):
error=sigmoid(matMatrix*w)-matLabel
w=w-alpha*matMatrix.transpose()*error
return w
#隨機梯度上升算法的實現,對於數據量較多的情況下計算量小,但分類效果差
#每次參數迭代時通過一個數據進行運算
def stocGraAscent(dataMatrix,matLabel):
m,n=shape(dataMatrix)
matMatrix=mat(dataMatrix)
w=ones((n,1))
alpha=0.001
num=20 #這里的這個迭代次數對於分類效果影響很大,很小時分類效果很差
for i in range(num):
for j in range(m):
error=sigmoid(matMatrix[j]*w)-matLabel[j]
w=w-alpha*matMatrix[j].transpose()*error
return w
#改進后的隨機梯度上升算法
#從兩個方面對隨機梯度上升算法進行了改進,正確率確實提高了很多
#改進一:對於學習率alpha采用非線性下降的方式使得每次都不一樣
#改進二:每次使用一個數據,但是每次隨機的選取數據,選過的不在進行選擇
def stocGraAscent1(dataMatrix,matLabel):
m,n=shape(dataMatrix)
matMatrix=mat(dataMatrix)
w=ones((n,1))
num=200 #這里的這個迭代次數對於分類效果影響很大,很小時分類效果很差
setIndex=set([])
for i in range(num):
for j in range(m):
alpha=4/(1+i+j)+0.01
dataIndex=random.randint(0,100)
while dataIndex in setIndex:
setIndex.add(dataIndex)
dataIndex=random.randint(0,100)
error=sigmoid(matMatrix[dataIndex]*w)-matLabel[dataIndex]
w=w-alpha*matMatrix[dataIndex].transpose()*error
return w
#繪制圖像
def draw(weight):
x0List=[];y0List=[];
x1List=[];y1List=[];
f=open('testSet.txt','r')
for line in f.readlines():
lineList=line.strip().split()
if lineList[2]=='0':
x0List.append(float(lineList[0]))
y0List.append(float(lineList[1]))
else:
x1List.append(float(lineList[0]))
y1List.append(float(lineList[1]))
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(x0List,y0List,s=10,c='red')
ax.scatter(x1List,y1List,s=10,c='green')
xList=[];yList=[]
x=arange(-3,3,0.1)
for i in arange(len(x)):
xList.append(x[i])
y=(-weight[0]-weight[1]*x)/weight[2]
for j in arange(y.shape[1]):
yList.append(y[0,j])
ax.plot(xList,yList)
plt.xlabel('x1');plt.ylabel('x2')
plt.show()
if __name__ == '__main__':
dataMatrix,matLabel=loadDataSet()
#weight=graAscent(dataMatrix,matLabel)
weight=stocGraAscent1(dataMatrix,matLabel)
print(weight)
draw(weight)