機(jī)器學(xué)習(xí)實(shí)戰(zhàn)
假設(shè)現(xiàn)在有一些數(shù)據(jù)點(diǎn),我們用一條直線對(duì)這些點(diǎn)進(jìn)行擬合(該線稱為最佳擬合直線),這個(gè)擬合過(guò)程就稱作回歸潘悼。Logistic回歸進(jìn)行分類的主要思想是:根據(jù)現(xiàn)有數(shù)據(jù)對(duì)分類邊界線監(jiān)理回歸公式,以此進(jìn)行分類。
基于Logistic回歸和Sigmoid函數(shù)
我們想要的函數(shù)應(yīng)該是外潜,能夠接受所有的輸入然后預(yù)測(cè)出類別。例如挠唆,在兩個(gè)類的情況下处窥,上述函數(shù)輸出0和1。從0瞬間跳躍到1玄组,這個(gè)跳躍的過(guò)程不好處理滔驾,我們引入Sigmoid函數(shù)。
此函數(shù)當(dāng)x = 0時(shí)俄讹,Sigmoid函數(shù)值為0.5哆致,隨著x的增大,對(duì)應(yīng)的Sigmoid值將逼近1患膛;而隨著x的減小摊阀,Sigmoid逼近于0。
因此為了實(shí)現(xiàn)Logistic回歸分類器,我們可以在每個(gè)特征上都乘以一個(gè)回歸系數(shù)胞此,然后把所有的結(jié)果值相加臣咖,將這個(gè)總和代入Sigmoid函數(shù)中,進(jìn)而得到一個(gè)范圍在0-1之間的數(shù)值豌鹤。 任何>0.5的數(shù)據(jù)被分入1類亡哄,<0.5的被歸為0類。
基于最優(yōu)化方法的最佳回歸系數(shù)的確定
Sigmoid的函數(shù)輸入記為z布疙,由下面公式得出:
用向量表示為蚊惯,表示將這兩個(gè)數(shù)值對(duì)應(yīng)元素相乘然后全部加起來(lái)得到z值。其中x是分類器的輸入數(shù)據(jù)灵临,向量w就是我們要找的最佳參數(shù)截型,從而使分類器盡可能精確。
接下來(lái)就是尋找最佳參數(shù)
梯度上升法 基于的思想是:要找到某個(gè)函數(shù)的最大值儒溉,最好的方法是沿著該函數(shù)的梯度方向探尋宦焦。如果梯度記為,這函數(shù)f(x,y)的梯度有下式表示:
如果所示梯度上升算法沿梯度方向移動(dòng)一步顿涣〔郑可以看到,梯度算子總是指向函數(shù)值增長(zhǎng)最快的方向涛碑。移動(dòng)量的大小稱為步長(zhǎng)精堕,記作。用向量來(lái)表示的話蒲障,梯度算法的迭代公司如下:
歹篓;該公式將一直迭代執(zhí)行,直至達(dá)到某個(gè)停止條件為止揉阎,比如迭代次數(shù)達(dá)到某個(gè)指定值或算法達(dá)到某個(gè)可以允許的誤差范圍庄撮。
from math import *
from numpy import *
import matplotlib.pyplot as plt
#加載數(shù)據(jù)
def loadDataSet():
dataMat = [];labelMat = []
fr = open('testSet.txt')
for line in fr.readlines():
lineArr = line.strip().split()
dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
def sigmoid(inX):
return 1.0/(1+exp(-inX))
'''
dataMatIn 是一個(gè)二維NumPy數(shù)組 每列代表不同的特征 每行代表一個(gè)訓(xùn)練樣本
classLabels 代表的是 樣本的類別
'''
def gradAscent(dataMatIn,classLabels):
dataMatrix = mat(dataMatIn)
# 轉(zhuǎn)換NumPy數(shù)據(jù)類型
labelMat = mat(classLabels).transpose()
m,n = shape(dataMatrix)
#向目標(biāo)移動(dòng)的步長(zhǎng)
alpha = 0.001
#迭代次數(shù)
maxCycles = 500
weights = ones((n,1))
for k in range(maxCycles):
h = sigmoid(dataMatrix*weights) #是一個(gè)列向量
error = (labelMat - h) #誤差 與真實(shí)值
weights = weights+alpha*dataMatrix.transpose()*error #調(diào)整
return weights
'''
繪圖 方便的API 步驟一樣 設(shè)置參數(shù)眾多
'''
def plitBestFit(weights):
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] #0 = w0x0+w1x1 計(jì)算x0的值
ax.plot(x,y)
plt.xlabel('X1')
plt.ylabel('X2')
plt.show()
if __name__ =='__main__':
dataArr,labelMat = loadDataSet()
# print(dataArr)
# print(labelMat)
weights = gradAscent(dataArr,labelMat)
# print(weights)
plitBestFit(weights.getA())
隨機(jī)梯度上升算法
梯度上升每次更新回歸系數(shù)時(shí)都需要遍歷整個(gè)數(shù)據(jù)集,該方法處理100個(gè)左右的數(shù)據(jù)集是尚可毙籽,但是如果數(shù)據(jù)量巨大洞斯,特征比較多,則該方法就不行坑赡。一種改進(jìn)的方法就是一次僅用一個(gè)樣本點(diǎn)來(lái)更新回歸系數(shù)巡扇,該方法稱為隨機(jī)梯度算法。
def stocGradAscent0(dataMatrix,classLabels):
m,n = shape(dataMatrix)
print(m,n)
alpha = 0.01
weights = ones(n)
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights)) #每一個(gè)樣本計(jì)算一次
error = classLabels[i] - h
weights = weights+alpha*error*dataMatrix[i]
return weights
if __name__ =='__main__':
dataArr,labelMat = loadDataSet()
# print(array(dataArr))
# print(labelMat)
weights = stocGradAscent0(array(dataArr),labelMat)
# # print(weights)
plitBestFit(weights)
可以看出最佳擬合直線并不是最佳分類線垮衷。
改進(jìn)
'''
默認(rèn)迭代150次,也可以自由設(shè)定迭代次數(shù)
1 每次迭代調(diào)整步長(zhǎng)
2隨機(jī)選取樣本來(lái)更新回歸系數(shù)乖坠。每次用列表中隨機(jī)取出一個(gè)值搀突,然后刪除
'''
def stocGradAscent1(dataMatrix,classLabels,numIter = 150):
m,n = shape(dataMatrix)
weights = ones(n)
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.0001 #1
randIndex = int(random.uniform(0,len(dataIndex))) #2
h = sigmoid(sum(dataMatrix[randIndex] * weights))
error = classLabels[randIndex] - h
weights = weights + alpha * error * dataMatrix[randIndex]
del(dataIndex[randIndex])
return weights