Logistic 迴歸
1.基本步驟
Logistic迴歸:實際上屬於判別分析,因擁有很差的判別效率而不常使用。
邏輯迴歸的一般過程
1) 收集數據:採用任意方法收集數據。
2) 準備數據:由於需要進行距離計算,因此要求數據類型爲數值型。另外,結構化數據格式則最佳。
3) 分析數據:採用任意方法對數據進行分析。
4) 訓練算法:大部分時間將用於訓練,訓練的目的是爲了找到最佳分類迴歸係數。
5) 測試算法:一旦訓練步驟完成,分類將會很快。
6) 使用算法:首先,我們需要輸入一些數據,並將其轉換成對應的結構化數值;接着,基於訓練好的迴歸係數就可以對這些數值進行簡單的迴歸計算,判定它們屬於哪個類型;在這之後,我們就可以在輸出的類別上作一些其他的分析工作。
優點:
1. 計算複雜度低,易於實施
2. 表示形式易於翻譯
缺點:
易於欠擬合,
2.原理
2.1常規步驟
Regression問題的常規步驟爲:
- 尋找h函數(即hypothesis);
- 構造J函數(log損失函數);
- 想辦法使得J函數最小並求得迴歸參數(θ)
2.2構造預測函數h
Logistic迴歸雖然名字裏帶“迴歸”,但是它實際上是一種分類方法,主要用於兩分類問題(即輸出只有兩種,分別代表兩個類別),所以利用了Logistic函數(或稱爲Sigmoid函數),函數形式爲:
Sigmoid 函數在有個很漂亮的“S”形,如下圖所示(引自維基百科):
下面左圖是一個線性的決策邊界,右圖是非線性的決策邊界。
對於線性邊界的情況,邊界形式如下:
構造預測函數爲:
函數的值有特殊的含義,它表示結果取1的概率,因此對於輸入x分類結果爲類別1和類別0的概率分別爲:
2.3構造損失函數J
損失函數使用log損失函數。Cost函數和J函數如下,它們是基於最大似然估計推導得到的。
下面詳細說明推導的過程:
(1)式綜合起來可以寫成:
取似然函數爲:
對數似然函數爲:
最大似然估計就是求使取最大值時的θ,其實這裏可以使用梯度上升法求解,求得的θ就是要求的最佳參數。但是,在Andrew Ng的課程中將取爲下式,即:
因爲乘了一個負的係數-1/m,所以取最小值時的θ爲要求的最佳參數。
梯度下降法求的最小值
θ更新過程:
θ更新過程可以寫成:
向量化Vectorization
Vectorization是使用矩陣計算來代替for循環,以簡化計算過程,提高效率。
如上式,Σ(...)是一個求和的過程,顯然需要一個for語句循環m次,所以根本沒有完全的實現vectorization。
下面介紹向量化的過程:
約定訓練數據的矩陣形式如下,x的每一行爲一條訓練樣本,而每一列爲不同的特稱取值:
g(A)的參數A爲一列向量,所以實現g函數時要支持列向量作爲參數,並返回列向量。由上式可知可由一次計算求得。
θ更新過程可以改爲:
綜上所述,Vectorization後θ更新的步驟如下:
(1)求;
(2)求;
(3)求 。
3.Python 求解Logistic 迴歸
訓練樣本當中有100個樣本,每個樣本有兩個特徵:X1和X2.
3.1 用梯度上升法尋找最優參數
def getData():
dataMat = []
labels=[]
fr = open('data/Ch05/testSet.txt')
for line in fr.readlines():
linearr=line.split()
dataMat.append([1.0,float(linearr[0]),float(linearr[1])])
labels.append(float(linearr[2]))
return dataMat,labels
def sigmod(intX):
result = []
for x in intX:
result.append( 1.0/(1+exp(-1.0*x)))
return result
def gradAscent(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn) #convert to NumPy matrix
labelMat = mat(classLabels).transpose() #convert to NumPy matrix
m,n = shape(dataMatrix)
alpha = 0.001
maxCycles = 500
weights = ones((n,1))
for k in range(maxCycles): #heavy on matrix operations
h = sigmoid(dataMatrix*weights) #matrix mult
error = (labelMat - h) #vector subtraction
weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
return weights
def plotBestFit(weights):
import matplotlib.pyplot as plt
dataMat,labels=getData()
dataArr = array(dataMat)
n = shape(dataMat)[0]
xcord1=[];ycord1=[]
xcord2=[];ycord2=[]
for i in range(n):
if int(labels[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)
plt.scatter(xcord1,ycord1,s=30,c='red',marker='s')
plt.scatter(xcord2,ycord2,s=30,c='green')
x=arange(-3.0,3.0,0.1)
weights=array(weights)
y=(-1*weights[0]-weights[1]*x)/weights[2]
y=array(y)
plt.plot(x,y)
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
3.2 用隨機梯度上升法尋找最優參數
def getData():
dataMat = []
labels=[]
fr = open('data/Ch05/testSet.txt')
for line in fr.readlines():
linearr=line.split()
dataMat.append([1.0,float(linearr[0]),float(linearr[1])])
labels.append(float(linearr[2]))
return dataMat,labels
def sigmod(intX):
result=1.0/(1+exp(-1.0*intX))
return result
def gradAscent(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn) #convert to NumPy matrix
labelMat = mat(classLabels).transpose() #convert to NumPy matrix
m,n = shape(dataMatrix)
alpha = 0.001
maxCycles = 500
weights = ones((n,1))
for k in range(maxCycles): #heavy on matrix operations
h = sigmoid(dataMatrix*weights) #matrix mult
error = (labelMat - h) #vector subtraction
weights = weights + alpha * dataMatrix.transpose()* error #matrix mult
return weights
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 plotBestFit(weights):
import matplotlib.pyplot as plt
dataMat,labels=getData()
dataArr = array(dataMat)
n = shape(dataMat)[0]
xcord1=[];ycord1=[]
xcord2=[];ycord2=[]
for i in range(n):
if int(labels[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)
plt.scatter(xcord1,ycord1,s=30,c='red',marker='s')
plt.scatter(xcord2,ycord2,s=30,c='green')
x=arange(-3.0,3.0,0.1)
weights=array(weights)
y=(-1*weights[0]-weights[1]*x)/weights[2]
y=array(y)
plt.plot(x,y)
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
3.3 用改進的隨機梯度上升法尋找最優參數
由於隨機訓練樣本比較少,所以用隨機梯度上升法求解結果較差,可以多運行幾次隨機梯度上升法同樣可以得到很好的結果。
def getData():
dataMat = []
labels=[]
fr = open('data/Ch05/testSet.txt')
for line in fr.readlines():
linearr=line.split()
dataMat.append([1.0,float(linearr[0]),float(linearr[1])])
labels.append(float(linearr[2]))
return dataMat,labels
def sigmod(intX):
if(intX>100):return 1.0
if(intX<-100):return 0.0
result = 1.0/(1+exp(-1.0*intX))
return result
def plotBestFit(weights):
import matplotlib.pyplot as plt
dataMat,labels=getData()
dataArr = array(dataMat)
n = shape(dataMat)[0]
xcord1=[];ycord1=[]
xcord2=[];ycord2=[]
for i in range(n):
if int(labels[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)
plt.scatter(xcord1,ycord1,s=30,c='red',marker='s')
plt.scatter(xcord2,ycord2,s=30,c='green')
x=arange(-3.0,3.0,0.1)
weights=array(weights)
y=(-1*weights[0]-weights[1]*x)/weights[2]
y=array(y)
plt.plot(x,y)
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
def stocGradAscent(dataMatrix,classLabels,numIter=150):
m,n=shape(dataMatrix)
weights=ones(n)
dataIndex =list(range(m))
for j in range(numIter):
for i in range(m):
alpha = 4/(1.0+i+j)+0.01
randIndex = int(random.uniform(0,len(dataIndex)))
h = sigmod(sum(dataMatrix[randIndex]*weights))
error = float(classLabels[randIndex])-h
weights=weights + alpha*error*dataMatrix[randIndex]
return weights