標籤:

機器學習-線性回歸與邏輯回歸

變數名介紹

  • m = 訓練集個數
  • n = 特徵個數
  • x = 輸入變數 / 特徵
  • y = 輸出變數 / 目標變數
  • 	heta = 參數
  • alpha = 學習速率
  • (x , y) = 一個樣本(訓練集中的一個)
  • (x^{(i)} , y^{(i)}) = 第 i 個樣本
  • x_{j}^{(i)} = 第 i 個樣本中的第 j 個特徵值(或與 	heta_{j} 對應的第 j 個輸入值)

線性回歸定義假設

假設 h 由訓練集經過學習演算法訓練得到,可以通過輸入特徵得到相應的預測

由於是線性回歸,我們假設:

h(x) = 	heta_{0}+	heta_{1}x_{1}+	heta_{2}x_{2}+...

為了簡化形式,我們假設 x_{0} = 1 ,那麼

h(x) = 	heta^{T}X

建立損失函數

現在我們擁有的是訓練集{ {(x^{(i)},y^{(i)});i=1,2,...,m} }與假設函數 h(x) = 	heta^{T}X ,我們需要做的是改變 	heta 的值讓 left| h_{	heta}(x)-y 
ight| 盡量小,使預測值與真值接近。

但是絕對值符號在打開的時候,存在判斷正負的問題,所以採用 (h_{	heta}(x)-y)^{2} 更好。

最後整合所有訓練集,建立損失函數 J(	heta)=1/2sum_{i=1}^{m}{}(h_{	heta}(x^{(i)})-y^{(i)})^{2} (乘了一個1/2是方便後面運算),此時我們需要做的就是求 J(	heta) 的最小值點。

梯度下降

在求函數 J(	heta) 最小值點的開始,我們設置了 	heta 的初始值,然後我們改變 	heta 值的策略就是向著梯度相反的方向,因為梯度的方向永遠是上升最快的方向。所以我們得到了更新 	heta 的方法:

	heta_{j}:=	heta_{j}-alphacdotfrac{partial}{partial 	heta_{j}}J(	heta)


為了更好的理解,可以舉一個不太靠譜的例子:

我們假設 J(	heta)=	heta^{2} ,我們同樣是求 J(	heta) 的最小值點,我們當然知道,就是 	heta=0 點。那麼當 	heta>0 時,我們利用更新 	heta 的方法得到:

	heta:=	heta-alphacdotfrac{d}{d	heta}J(	heta)

其中 frac{d}{d	heta}J(	heta)=2	heta ,所以:

	heta:=	heta-alphacdot2	heta=(1-2alpha)	heta

由於 alpha>0 ,所以只要 alpha<1 ,那麼 	heta 的值就會更加靠近0,同時 J(	heta) 也會變小。經過不斷的迭代後就會收斂到最小值點 	heta=0

在這個例子里,我們也可以理解 alpha 為什麼叫學習速率。

0<alphaleq0.5 的條件下,在alpha 越小,迭代次數就會越多, alpha 越大,迭代次數就會越少,並且在 alpha=0.5 時一步就收斂。

0.5<alphaleq1 的條件下,將會發生震蕩。

alpha>1 的條件下,將會發散。

所以可以看到 alpha 的大小在訓練過程中也很重要。


書接上文,我們得到了更新 	heta 的方法,把 J(	heta) 帶入,得到:

所以整合所有訓練集,我們得到了完成的更新 	heta 的方法:

	heta_{j}:=	heta_{j}-alphacdotsum_{i=1}^{m}{(h_{	heta}(x^{(i)})-y^{(i)})x_{j}^{(i)}} (for every j)

當數據量太大時,我們可以採取隨機梯度下降(SGD)的方法:

for i to m {	heta_{j}:=	heta_{j}-alphacdot(h_{	heta}(x^{(i)})-y^{(i)})x_{j}^{(i)} (for every j)}

矩陣求解

針對線性回歸,我們可以直接求解 	heta 的值:

	heta=(X^{T}X)^{-1}X^{T}y

由於存在矩陣的逆,所以不容易計算,並且可能不存在。

局部加權回歸

局部加權回歸可以看作時線性回歸的一種推廣,他可以擬合除了線性之外其他的模型。

首先引入兩個變數:

  • omega^{(i)} = 第 i 組訓練數據對應的權值
  • 	au = 波長(控制權值隨距離下降的速率,越小下降越快,越大下降越慢)

改變損失函數為:

sum_{}^{}{omega^{(i)}(y^{(i)}-	heta^{T}x^{(i)})^{2}}

其中:

omega^{(i)}=e^{-frac{(x^{(i)}-x)^{2}}{2	au^{2}}} (也可以採用其他函數,只要滿足下面的性質即可,常用這個)

所以在 left| x^{(i)}-x 
ight|
ightarrow0 的時候, omega^{(i)}
ightarrow1

left| x^{(i)}-x 
ight|
ightarrowinfty 的時候, omega^{(i)}
ightarrow0

並且由 	au 來控制 omega 隨距離大小下降的速率。

omega^{(i)} 中是存在輸入變數 x 的,在每一次擬合之前都需要知道輸入變數 x 的大小,即在每次預測之前都需要重新訓練。並且離輸入變數 x 越遠的樣本對於損失函數的貢獻就越小,若我們把貢獻小的樣本去掉,其實局部線性回歸就是利用預測值附近的樣本擬合了一條直線之後,再進行預測的。

線性回歸的概率解釋

首先我們假設:

其中epsilon^{(i)} 可以看作誤差,並且該誤差服從高斯分布:epsilon^{(i)}sim N(0,sigma^{2}) ,即:

然後我們利用極大似然估計相同的方法,選擇 	heta 值使得概率最大:

為了使整個函數值最大化,我們需要函數中如下圖的部分的值盡量小:

即得到了之前設計得損失函數,也說明該損失函數是有概率意義的。

邏輯回歸

由於邏輯回歸用來分類,所以 yinleft{ 0,1 
ight}h_{	heta}inleft[ 0,1 
ight]

設置激活函數:g(z)=frac{1}{1+e^{-z}} ,函數圖像如下圖:

可以看到函數值的範圍在 left( 0,1 
ight) 之間,並且在 z=0 處值 0.5 。

同時定義函數 h_{	heta}(x)=g(	heta^{T}x)=frac{1}{1+e^{-	heta^{T}x}} ,計算結果時,以0.5為區分界限,大於0.5即為1,小於0.5即為0。

梯度上升

接下來計算我們需要設置目標函數,並且得到 	heta 的更新方法,我們採用概率的方法實現。

首先得到概率解釋:

由於 yinleft{ 0,1 
ight} ,所以可以整合在一起:

同時利用與極大似然估計相同的方法:

為了方便操作,進行如下操作:

為了改變 	heta 使 l(	heta) 取得最大值,我們採用梯度上升的方法:

	heta_{j}:=	heta_{j}+alphacdotfrac{partial}{partial 	heta_{j}}l(	heta)

化簡操作如下:

得到最後的 	heta 更新方法:

	heta_{j}:=	heta_{j}+alphacdotsum_{i=1}^{m}{(y^{(i)}-h_{	heta}(x^{(i)}))x_{j}^{(i)}}

實際上這個更新方法與線性回歸看似是一樣的,但是實際上是不同的,因為 h_{	heta}(x) 是不同的。

感知器

我們可以把上節中的 g(z) 變成感知器函數:

可以得到與激活函數相同的結果,這可以看作邏輯回歸的特性,即:

	heta_{j}:=	heta_{j}+alphacdotsum_{i=1}^{m}{(y^{(i)}-h_{	heta}(x^{(i)}))x_{j}^{(i)}}

牛頓方法

牛頓方法是如同梯度上升一樣相同的,迭代更新 	heta 的方法,但是它的限制條件會多一點,但是迭代速度一般都比梯度上升方法更快。

為了介紹牛頓方法,首先假設函數 f(	heta) ,為了找到 f(	heta)=0 的點。在選取了 	heta 的初始值後,我們可以利用如下的方法更新 	heta

	heta:=	heta-frac{f(	heta)}{f^{}(	heta)} ,直至收斂。

其實際的物理意義如下圖所示:

即每次更新 	heta的值為, (	heta,f(	heta)) 點處的切線與 x 軸相交的點,迭代至收斂後就會得到 f(	heta)=0 的點。

但是我們需要利用牛頓方法來替代梯度上升方法,之前我們利用梯度上升的方法來尋找 l(	heta) 的最大值,實際上也是求 l^{}(	heta)=0 的點。這樣我們可以利用牛頓方法來求解,即將 l^{}(	heta) 看作上面的 f(x)

所以在邏輯回歸里利用牛頓方法,我們就可以利用如下方法更新 	heta

	heta:=	heta-frac{l^{}(	heta)}{l^{}(	heta)}

我們可以如下化簡:

其中 H 為Hessian Matrix,如下所示:

牛頓方法迭代的速度一般遠遠快於梯度下降方法。

廣義線性模型

廣義線性模型可以看作線性回歸與邏輯回歸的一種普通情況,並且我們可以知道只要我們假設概率模型為指數分布簇,我們就可以利用廣義線性模型解決。(同時也是利用極大似然估計來計算)

指數分布簇如下:

p(y;eta)=b(y)exp(eta^{T}T(y)-a(eta)) ,通過設置T(y),b(y),a( eta )來得到不同的概率分布。

主要流程如下:

  1. 假設概率模型 y|x;	heta ,服從ExpFamily( eta ),即指數分布簇。
  2. 給定x,目標輸出為 h(x)=Eleft[ T(y)|x 
ight] ,大多數情況下 T(y)=y
  3. eta=	heta^{T}x

總結

針對判別式學習演算法,我們需要做的主要是以下幾個步驟:

  1. 假設 y|x;	heta 概率分布(若是線性模型,則為指數分布)。
  2. 得到目標輸出 h_{	heta}(x) (廣義線性模型中為 Eleft[ T(y)|x 
ight] )。
  3. 利用極大似然估計求得 	heta
  4. 利用函數 h_{	heta}(x) 預測結果。

參考

  • Andrew Ng的機器學習公開課。

線性回歸代碼

房屋數據(data.txt):

2104,3,3999001600,3,3299002400,3,3690001416,2,2320003000,4,5399001985,4,2999001534,3,3149001427,3,1989991380,3,2120001494,3,2425001940,4,2399992000,3,3470001890,3,3299994478,5,6999001268,3,2599002300,4,4499001320,2,2999001236,3,1999002609,4,4999983031,4,5990001767,3,2529001888,2,2550001604,3,2429001962,4,2599003890,3,5739001100,3,2499001458,3,4645002526,3,4690002200,3,4750002637,3,2999001839,2,3499001000,1,1699002040,4,3149003137,3,5799001811,4,2859001437,3,2499001239,3,2299002132,4,3450004215,4,5490002162,4,2870001664,2,3685002238,3,3299002567,4,3140001200,3,299000852,2,1799001852,4,2999001203,3,239500

代碼:

# -*- coding: utf-8 -*-"""第一個版本:1.按照學習筆記實現"""import numpy as npdef load_data(path): """ 功能:讀取訓練數據 參數:數據文件路徑 返回:訓練集與標籤矩陣 """ x = [] y = [] file_in = open(path) for line in file_in.readlines(): s_data = line.strip().split(,) # strip()函數去除換行符,split()函數分割數據 temp = [] temp.append(1.0) # 設置x0 = 1 if len(s_data) < 2: print "輸入數據錯誤" for i in range(len(s_data) - 1): temp.append(float(s_data[i])) x.append(temp) y.append(float(s_data[len(s_data) - 1])) return np.mat(x), np.mat(y).transpose() # 轉化為矩陣def J(x, y, theta): """ 功能:損失函數 參數:數據集,參數 返回:損失值 """ delta = x * theta - y ws = 0.5 * delta.transpose() * delta return wsdef train(x, y, alpha, maxIter): """ 功能:訓練函數 參數:訓練集,學習速率,最大迭代次數 返回:參數 """ theta = np.ones((x.shape[1], 1)) for i in range(maxIter): delta = x.transpose() * (x * theta - y) theta = theta - alpha * delta print J(x, y, theta) return thetaif __name__ == __main__: train_x, train_y = load_data(data.txt) theta = train(train_x, train_y, 0.0000000005, 200) print train_x * theta

在設置學習速率時,是從 1 開始不斷減小測試的,到大約為0.0000000005時開始收斂,學習速率非常難修改,且收斂後預測效果並不好,主要因為數據沒有預處理。(注意最後測試時用的也是訓練集,是不對的,但是這裡數據量太小。)

增加數據預處理,SGD訓練方法,epoch的概念:

# -*- coding: utf-8 -*-"""第二個版本:1.由於學習速率不好設置,所以增加數據預處理,即標準化2.增加SGD訓練"""import numpy as npdef load_data(path): """ 功能:讀取訓練數據 參數:數據文件路徑 返回:訓練集與標籤矩陣 """ x = [] y = [] file_in = open(path) for line in file_in.readlines(): s_data = line.strip().split(,) temp = [] temp.append(1.0) if len(s_data) < 2: print "輸入數據錯誤" for i in range(len(s_data) - 1): temp.append(float(s_data[i])) x.append(temp) y.append(float(s_data[len(s_data) - 1])) return np.mat(x), np.mat(y).transpose()def data_preprocessing(x): """ 功能:數據預處理 參數:數據集 返回:處理後數據,均值,標準差 """ m, n = x.shape miu = np.zeros((n, 1)) sigma = np.zeros((n, 1)) for i in range(n): miu[i] = np.mean(x[:, i]) # 計算均值 sigma[i] = np.std(x[:, i]) # 計算標準差 for j in range(m): x[j, 1:] = np.divide(x[j, 1:] - miu[1:].transpose(), sigma[1:].transpose()) return x, miu, sigmadef J(x, y, theta): """ 功能:損失函數 參數:數據集,參數 返回:損失值 """ delta = x * theta - y ws = 0.5 * delta.transpose() * delta return wsdef train(x, y, alpha, maxIter): """ 功能:訓練函數 參數:訓練集,標籤,學習速率,最大迭代次數 返回:參數 """ theta = np.ones((x.shape[1], 1)) for i in range(maxIter): delta = x.transpose() * (x * theta - y) theta = theta - alpha * delta print "Iter:" + str(i+1), " J:" + str(J(x, y, theta).tolist()[0][0]) return thetadef train_SGD(x, y, alpha, maxEpoch): """ 功能:訓練函數(SGD) 參數:訓練集,標籤,學習速率,最大迭代次數 返回:參數 """ theta = np.ones((x.shape[1], 1)) for i in range(maxEpoch): # 每次迭代 for j in range(x.shape[0]): # 每個參數 delta = x[j, :].transpose() * (x[j, :] * theta - y[j, :]) theta = theta - alpha * delta print "Epoch:" + str(i + 1), " Iter:" + str(i * maxEpoch + j), " J:" + str(J(x, y, theta).tolist()[0][0]) return thetaif __name__ == __main__: train_x, train_y = load_data(data.txt) pre_train_x, miu, sigma = data_preprocessing(train_x) # theta = train(train_x, train_y, 0.02, 20) theta = train_SGD(train_x, train_y, 0.02, 20) print pre_train_x * theta

邏輯回歸代碼

數據(data.txt):

34.62365962451697,78.0246928153624,030.28671076822607,43.89499752400101,035.84740876993872,72.90219802708364,060.18259938620976,86.30855209546826,179.0327360507101,75.3443764369103,145.08327747668339,56.3163717815305,061.10666453684766,96.51142588489624,175.02474556738889,46.55401354116538,176.09878670226257,87.42056971926803,184.43281996120035,43.53339331072109,195.86155507093572,38.22527805795094,075.01365838958247,30.60326323428011,082.30705337399482,76.48196330235604,169.36458875970939,97.71869196188608,139.53833914367223,76.03681085115882,053.9710521485623,89.20735013750205,169.07014406283025,52.74046973016765,167.94685547711617,46.67857410673128,070.66150955499435,92.92713789364831,176.97878372747498,47.57596364975532,167.37202754570876,42.83843832029179,089.67677575072079,65.79936592745237,150.534788289883,48.85581152764205,034.21206097786789,44.20952859866288,077.9240914545704,68.9723599933059,162.27101367004632,69.95445795447587,180.1901807509566,44.82162893218353,193.114388797442,38.80067033713209,061.83020602312595,50.25610789244621,038.78580379679423,64.99568095539578,061.379289447425,72.80788731317097,185.40451939411645,57.05198397627122,152.10797973193984,63.12762376881715,052.04540476831827,69.43286012045222,140.23689373545111,71.16774802184875,054.63510555424817,52.21388588061123,033.91550010906887,98.86943574220611,064.17698887494485,80.90806058670817,174.78925295941542,41.57341522824434,034.1836400264419,75.2377203360134,083.90239366249155,56.30804621605327,151.54772026906181,46.85629026349976,094.44336776917852,65.56892160559052,182.36875375713919,40.61825515970618,051.04775177128865,45.82270145776001,062.22267576120188,52.06099194836679,077.19303492601364,70.45820000180959,197.77159928000232,86.7278223300282,162.07306379667647,96.76882412413983,191.56497449807442,88.69629254546599,179.94481794066932,74.16311935043758,199.2725269292572,60.99903099844988,190.54671411399852,43.39060180650027,134.52451385320009,60.39634245837173,050.2864961189907,49.80453881323059,049.58667721632031,59.80895099453265,097.64563396007767,68.86157272420604,132.57720016809309,95.59854761387875,074.24869136721598,69.82457122657193,171.79646205863379,78.45356224515052,175.3956114656803,85.75993667331619,135.28611281526193,47.02051394723416,056.25381749711624,39.26147251058019,030.05882244669796,49.59297386723685,044.66826172480893,66.45008614558913,066.56089447242954,41.09209807936973,040.45755098375164,97.53518548909936,149.07256321908844,51.88321182073966,080.27957401466998,92.11606081344084,166.74671856944039,60.99139402740988,132.72283304060323,43.30717306430063,064.0393204150601,78.03168802018232,172.34649422579923,96.22759296761404,160.45788573918959,73.09499809758037,158.84095621726802,75.85844831279042,199.82785779692128,72.36925193383885,147.26426910848174,88.47586499559782,150.45815980285988,75.80985952982456,160.45555629271532,42.50840943572217,082.22666157785568,42.71987853716458,088.9138964166533,69.80378889835472,194.83450672430196,45.69430680250754,167.31925746917527,66.58935317747915,157.23870631569862,59.51428198012956,180.36675600171273,90.96014789746954,168.46852178591112,85.59430710452014,142.0754545384731,78.84478600148043,075.47770200533905,90.42453899753964,178.63542434898018,96.64742716885644,152.34800398794107,60.76950525602592,094.09433112516793,77.15910509073893,190.44855097096364,87.50879176484702,155.48216114069585,35.57070347228866,074.49269241843041,84.84513684930135,189.84580670720979,45.35828361091658,183.48916274498238,48.38028579728175,142.2617008099817,87.10385094025457,199.31500880510394,68.77540947206617,155.34001756003703,64.9319380069486,174.77589300092767,89.52981289513276,1

邏輯回歸與線性回歸相比需要修改損失函數為極大似然估計中的 l(theta) ,利用梯度上升求得使 l(theta) 取得最大值時的參數。代碼如下:

# -*- coding: utf-8 -*-"""第一個版本"""import numpy as npdef load_data(path): """ 功能:讀取訓練數據 參數:數據文件路徑 返回:訓練集與標籤矩陣 """ x = [] y = [] file_in = open(path) for line in file_in.readlines(): s_data = line.strip().split(,) temp = [] temp.append(1.0) if len(s_data) < 2: print "輸入數據錯誤" for i in range(len(s_data) - 1): temp.append(float(s_data[i])) x.append(temp) y.append(float(s_data[len(s_data) - 1])) return np.mat(x), np.mat(y).transpose()def data_preprocessing(x): """ 功能:數據預處理 參數:數據集 返回:處理後數據,均值,標準差 """ m, n = x.shape miu = np.zeros((n, 1)) sigma = np.zeros((n, 1)) for i in range(n): miu[i] = np.mean(x[:, i]) sigma[i] = np.std(x[:, i]) for j in range(m): x[j, 1:] = np.divide(x[j, 1:] - miu[1:].transpose(), sigma[1:].transpose()) return x, miu, sigmadef l(x, y, theta): """ 功能:極大似然估計概率函數l(theta) 參數:數據集,參數 返回:損失值 """ delta = sigmoid(x * theta) costs = y.transpose() * np.log(delta) + (1.0 - y).transpose() * np.log(1.0 - delta) return sum(costs)def train(x, y, alpha, maxIter): """ 功能:訓練函數(變為梯度上升) 參數:訓練集,標籤,學習速率,最大迭代次數 返回:參數 """ theta = np.ones((x.shape[1], 1)) for i in range(maxIter): delta = y - sigmoid(x * theta) theta = theta + alpha * x.transpose() * delta print "Iter:" + str(i+1), " Alpha:" + str(alpha), " l:" + str(l(x, y, theta).tolist()[0][0]) return thetadef train_SGD(x, y, alpha, maxEpoch): """ 功能:訓練函數(SGD) 參數:訓練集,標籤,學習速率,最大迭代次數 返回:參數 """ theta = np.ones((x.shape[1], 1)) for i in range(maxEpoch): # 每次迭代 for j in range(x.shape[0]): #每個參數 delta = x[j, :].transpose() * (y[j, :] - sigmoid(x[j, :] * theta)) theta = theta + alpha * delta print "Epoch:" + str(i + 1), " Iter:" + str(i * maxEpoch + j), " l:" + str(l(x, y, theta).tolist()[0][0]) return thetadef sigmoid(z): """ 功能:sigmoid函數 參數:輸入矩陣 返回:輸出矩陣 """ return 1.0 / (1 + np.exp(-z))def test_accuracy(x, y, theta): """ 功能:計算測試準確率 參數:訓練集,標籤,參數 返回:準確率 """ m = x.shape[0] num = 0 predict_y = sigmoid(x * theta) # 預測值 difference = np.abs(y - predict_y).tolist() # 計算預測值與標籤的差值的絕對值,小於0.5則預測正確,否則預測錯誤 for i in range(m): if difference[i][0] < 0.5: num += 1 return num / float(m)if __name__ == __main__: train_x, train_y = load_data(data.txt) pre_train_x, miu, sigma = data_preprocessing(train_x) theta = train(train_x, train_y, 0.01, 100) # theta = train_SGD(train_x, train_y, 0.02, 20) print theta print test_accuracy(pre_train_x, train_y, theta)

在進行測試時,由於數據少,我們還是訓練集與測試集用的同一個數據集。在學習速率為0.01時,我們訓練到收斂後,得到的準確率為0.89。但是當我們將學習速率設置為0.0001時,在收斂後我們得到的準確率為0.91。在參數值接近最優解的時候,我們需要減小學習速率才會更加接近最優解,學習速率太大可能產生震蕩。所以應該隨著迭代次數的增加不斷減小學習速率。修改如下:

# -*- coding: utf-8 -*-"""第二個版本:1.修改學習速率隨迭代次數而減小,盡量少的迭代次數得到更高的準確率"""import numpy as npdef load_data(path): """ 功能:讀取訓練數據 參數:數據文件路徑 返回:訓練集與標籤矩陣 """ x = [] y = [] file_in = open(path) for line in file_in.readlines(): s_data = line.strip().split(,) temp = [] temp.append(1.0) if len(s_data) < 2: print "輸入數據錯誤" for i in range(len(s_data) - 1): temp.append(float(s_data[i])) x.append(temp) y.append(float(s_data[len(s_data) - 1])) return np.mat(x), np.mat(y).transpose()def data_preprocessing(x): """ 功能:數據預處理 參數:數據集 返回:處理後數據,均值,標準差 """ m, n = x.shape miu = np.zeros((n, 1)) sigma = np.zeros((n, 1)) for i in range(n): miu[i] = np.mean(x[:, i]) sigma[i] = np.std(x[:, i]) for j in range(m): x[j, 1:] = np.divide(x[j, 1:] - miu[1:].transpose(), sigma[1:].transpose()) return x, miu, sigmadef l(x, y, theta): """ 功能:極大似然估計概率函數l(theta) 參數:數據集,參數 返回:損失值 """ delta = sigmoid(x * theta) costs = y.transpose() * np.log(delta) + (1.0 - y).transpose() * np.log(1.0 - delta) return sum(costs)def train(x, y, alpha, maxIter, alpha_rate): """ 功能:訓練函數(變為梯度上升) 參數:訓練集,標籤,學習速率,最大迭代次數,學習速率下降速度 返回:參數 """ theta = np.ones((x.shape[1], 1)) for i in range(maxIter): delta = y - sigmoid(x * theta) theta = theta + alpha * x.transpose() * delta alpha -= alpha_rate * alpha print "Iter:" + str(i+1), " l:" + str(l(x, y, theta).tolist()[0][0]) return thetadef train_SGD(x, y, alpha, maxEpoch, alpha_rate): """ 功能:訓練函數(SGD) 參數:訓練集,標籤,學習速率,最大迭代次數,學習速率下降速度 返回:參數 """ theta = np.ones((x.shape[1], 1)) for i in range(maxEpoch): for j in range(x.shape[0]): delta = x[j, :].transpose() * (y[j, :] - sigmoid(x[j, :] * theta)) theta = theta + alpha * delta alpha -= alpha_rate * alpha print "Epoch:" + str(i + 1), " Iter:" + str(i * maxEpoch + j), " l:" + str(l(x, y, theta).tolist()[0][0]) return thetadef sigmoid(z): """ 功能:sigmoid函數 參數:輸入矩陣 返回:輸出矩陣 """ return 1.0 / (1 + np.exp(-z))def test_accuracy(x, y, theta): """ 功能:計算測試準確率 參數:訓練集,標籤,參數 返回:準確率 """ m = x.shape[0] num = 0 predict_y = sigmoid(x * theta) difference = np.abs(y - predict_y).tolist() for i in range(m): if difference[i][0] < 0.5: num += 1 return num / float(m)if __name__ == __main__: train_x, train_y = load_data(data.txt) pre_train_x, miu, sigma = data_preprocessing(train_x) theta = train(train_x, train_y, 0.01, 100, 0.2) # theta = train_SGD(train_x, train_y, 0.02, 15, 0.02) print theta print test_accuracy(pre_train_x, train_y, theta)

在每次迭代後alpha的大小都會減去本身的alpha_rate倍,實現alpha隨著迭代次數增加而減小。最後使用正常的梯度下降達到了0.92的準確率,使用SGD達到了0.93的準確率。


推薦閱讀:

導數、偏導、次梯度關係
正經機器學習之小巧的流程可視化機器學習工具
kaggle實戰-房價預測
通俗講解P(查准率),R(查全率),F1值
深度森林(deep forest)

TAG:機器學習 |