Sigmod函數
logist回歸首先是一種分類方法曼库,作為一種分類方法此衅,它具有一個先驗概率分布:伯努利分布济欢。因此Sigmod函數具有同指數族分布一樣的形式脆贵。
![][equtation1]
[equtation1]: http://latex.codecogs.com/svg.latex?\sigma=\frac{1}{1+{e^{-z}}}
復習:指數組分布有哪些?
- 伯努利分布(Bernoulli)量蕊;
- 多項式分布(Multinomial)羡亩;
- 泊松分布(Poisson);
- 伽馬分布(gamma)與指數分布(exponential):對有間隔的正數進行建模危融,比如公交車的到站時間問題;
- β 分布:對小數建模雷袋;
- Dirichlet 分布:對概率分布進建模吉殃;
- Wishart 分布:協方差矩陣的分布;
- 高斯分布(Gaussian)楷怒;
上面這些分布都可以化為Sigmod函數的形式蛋勺,關于這些分布的問題,可以被歸為廣義線性模型鸠删。
觀察圖像可知抱完,Sigmod函數看起來表現為一個階躍函數的形式,sigmoid函數是一個良好的閾值函數刃泡。具有如下優(yōu)點:
- 連續(xù)巧娱,光滑
- 嚴格單調
- 關于(0,0.5)中心對稱
- 對閾值函數f(x)的近似得很良好
1, x > 0
/
f(x)=
\
0, x < 0
- 其導數f'(x)=f(x)*[1-f(x)]碉怔,可以節(jié)約計算時間
我們可以據此給每個特征都乘上一個回歸系數,然后把所有結果相加禁添,將這個總和帶入z撮胧。
![][equtation1]
[equtation1]: http://latex.codecogs.com/svg.latex?\sigma=\frac{1}{1+{e^{-z}}}
其中:
![][equtation2]
[equtation2]: http://latex.codecogs.com/svg.latex?z=w_{0}x_{0}+w_{1}x_{1}+\cdots+w_{n}x_{n}
以向量形式表達就是:
![][equtation3]
[equtation3]: http://latex.codecogs.com/svg.latex?z=w^{T}x
于是我們可以找到一個最佳參數w,盡可能得使分類趨于理想的結果老翘。這種通過訓練數據找到分類界面的方法非常類似于線性回歸芹啥,因此它也被叫做logistc回歸。
如何確定這個界面墓怀,也就是找到w這組最佳系數,方法同線性回歸類似卫键,有最小二乘傀履、梯度上升等方法,前者不再贅述永罚,這里只說梯度上升(下降)法啤呼。
梯度上升法
首先要聲明的是,梯度上升和梯度下降都是一回事呢袱,只是公式中的假發(fā)需要改為減法官扣,原理都是沿著梯度找局部最優(yōu)。原理在線性回歸中已經寫出來過羞福,就不再贅述了惕蹄,這里只介紹算法。
偽代碼如下:
每個回歸系數初始化為1
重復R次:
計算整個數據集的梯度
是有alpha*gradient更新回歸系數的向量
返回回歸系數
代碼實例:
MLR已經替我們把數據已經洗好了治专,首先預覽一下:
-0.017612 14.053064 0
-1.395634 4.662541 1
-0.752157 6.538620 0
-1.322371 7.152853 0
0.423363 11.054677 0
0.406704 7.067335 1
可以看到第一列是x1,第二列為x2,最后一列是類別卖陵。
總之代碼如下:
# -*-coding:utf-8 -*-
from numpy import *
#數據載入函數
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
#Sigmoid函數
def sigmoid(inX):
return 1.0/(1+exp(-inX))
#梯度下降函數
def gradAscent(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn) #搞成NumPy矩陣
labelMat = mat(classLabels).transpose()
m,n = shape(dataMatrix) #m行n列
alpha = 0.001 #定義步長
maxCycles = 500 #迭代次數
weights = ones((n,1)) #初始化w,一個全是1的列向量
for k in range(maxCycles): #循環(huán)固定次數
h = sigmoid(dataMatrix*weights)
#h是一個列向量张峰,維度等于樣本個數泪蔫,該數據有100個
error = (labelMat - h) #算個差值
weights = weights + alpha * dataMatrix.transpose()* error
#按照差值的方向調整系數
return weights
if __name__ == '__main__':
dataArr, labelMat = loadDataSet()
weights = gradAscent(dataArr, labelMat)
print weights
返回值也可以看一下:
[[ 4.12414349]
[ 0.48007329]
[-0.6168482 ]]
當然我們沒有忘記可視化是很重要的,于是我們試著畫個圖看看:
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()
if __name__ == '__main__':
dataArr, labelMat = loadDataSet()
weights = gradAscent(dataArr, labelMat)
print weights
plotBestFit(weights.getA())
#getA()是np矩陣方法喘批,作為ndarray返回自己
得到下圖:
這個方法好是挺好的撩荣,但因為用了300次乘法,所以不太適用于較大數據饶深,所以我們再來搞個隨機梯度看看餐曹。
隨機梯度上升(Stochastic Gradient)
首先,單純的梯度上升在每次更新w時都需要遍歷整個數據集敌厘,小數據尚可台猴,對于大數據沒什么可行性,對于這種算法我們把它叫做批處理。
相對應的饱狂,還有一種算法我們每次更新僅用一個樣本點曹步,這種方法叫做在線學習。
偽代碼:
所有回歸系數初始化為1
對數據集中每個樣本
計算該樣本的梯度
使用alpha*gradient更新回歸系數值
返回回歸系數值
代碼如下:
def stocGradAscent0(dataMatrix, classLabels):
m,n = shape(dataMatrix)
alpha = 0.01
weights = ones(n) #初始化w嗡官,一個全是1的行向量
for i in range(m):
h = sigmoid(sum(dataMatrix[i]*weights))
error = classLabels[i] - h
weights = weights + alpha * error * dataMatrix[i]
return weights
if __name__ == '__main__':
weights2 = stocGradAscent0(array(dataArr), labelMat)
print weights2
plotBestFit(weights2)
看看返回的w箭窜,好像跟第一個相差很大啊穴张。
[ 1.01702007 0.85914348 -0.36579921]
畫的圖也完全不能接受啊毒坛,肯定是哪里出了問題。
仔細思考一下磅网,這個算法到底哪里出了問題婆咸?原來是步長的問題V褡健!
步長過小尚骄,收斂太慢块差;步長太小,收斂不到局部最優(yōu)解倔丈。
所以我們需要對算法改進一下憨闰,得到有一個動態(tài)步長。
#默認迭代次數是150次需五,可以通過參數修改
def stocGradAscent1(dataMatrix, classLabels, numIter=150):
m,n = shape(dataMatrix)
weights = ones(n) #initialize to all ones
for j in range(numIter):
dataIndex = range(m)
for i in range(m):
alpha = 4/(1.0+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]
del(dataIndex[randIndex])
#每次從列表中隨機選一個值,然后刪掉
return weights
最后得到的結果是:
[ 13.10360032 0.65123109 -1.75151716]
好像還能接受宏邮。