本文參考公共號《數據科學家聯盟》餅乾文章。html
1、簡單線性迴歸:簡單線性迴歸及最小二乘法的數據推導python
所謂簡單,是指只有一個樣本特徵,即只有一個自變量;所謂線性,是指方程是線性的;所謂迴歸,是指用方程來模擬變量之間是如何關聯的。 簡單線性迴歸,其思想簡單,實現容易(與其背後強大的數學性質相關。同時也是許多強大的非線性模型(多項式迴歸、邏輯迴歸、SVM)的基礎。而且其結果具備很好的可解釋性。算法
一、推導思路:機器學習
找到一組參數,使得真實值與預測值之間的差距儘量地小,是一種典型的機器學習算法的推導思路函數
咱們所謂的建模過程,其實就是找到一個模型,最大程度的擬合咱們的數據。 在簡單線迴歸問題中,模型就是咱們的直線方程:y = ax + b 。 要想最大的擬合數據,本質上就是找到沒有擬合的部分,也就是損失的部分儘可能小,就是損失函數(loss function)(也有算法是衡量擬合的程度,稱函數爲效用函數(utility function)):學習
所以,推導思路爲: 1.經過分析問題,肯定問題的損失函數或者效用函數; 2.而後經過最優化損失函數或者效用函數,得到機器學習的模型 近乎全部參數學習算法都是這樣的套路,區別是模型不一樣,創建的目標函數不一樣,優化的方式也不一樣。 回到簡單線性迴歸問題,目標:測試
已知訓練數據樣本X、y ,找到a和b的值,使儘量小大數據
這是一個典型的最小二乘法問題(最小化偏差的平方) 經過最小二乘法能夠求出a、b的表達式:優化
在機器學習中,全部的算法模型其實都依賴於最小化或最大化某一個函數,咱們稱之爲「目標函數」。 最小化的這組函數被稱爲「損失函數」。什麼是損失函數呢?spa
損失函數描述了單個樣本預測值和真實值之間偏差的程度。用來度量模型一次預測的好壞。
損失函數是衡量預測模型預測指望結果表現的指標。損失函數越小,模型的魯棒性越好。。 經常使用損失函數有:
0-1損失函數:用來表述分類問題,當預測分類錯誤時,損失函數值爲1,正確爲0
平方損失函數:用來描述迴歸問題,用來表示連續性變量,爲預測值與真實值差值的平方。(偏差值越大、懲罰力度越強,也就是對差值敏感)
絕對損失函數:用在迴歸模型,用距離的絕對值來衡量
對數損失函數:是預測值Y和條件機率之間的衡量。事實上,該損失函數用到了極大似然估計的思想。P(Y|X)通俗的解釋就是:在當前模型的基礎上,對於樣本X,其預測值爲Y,也就是預測正確的機率。因爲機率之間的同時知足須要使用乘法,爲了將其轉化爲加法,咱們將其取對數。最後因爲是損失函數,因此預測正確的機率越高,其損失值應該是越小,所以再加個負號取個反。
以上損失函數是針對於單個樣本的,可是一個訓練數據集中存在N個樣本,N個樣本給出N個損失,如何進行選擇呢? 這就引出了風險函數。
指望風險是損失函數的指望,用來表達理論上模型f(X)關於聯合分佈P(X,Y)的平均意義下的損失。又叫指望損失/風險函數。
模型f(X)關於訓練數據集的平均損失,稱爲經驗風險或經驗損失。 其公式含義爲:模型關於訓練集的平均損失(每一個樣本的損失加起來,而後平均一下)
經驗風險最小的模型爲最優模型。在訓練集上最小經驗風險最小,也就意味着預測值和真實值儘量接近,模型的效果越好。公式含義爲取訓練樣本集中對數損失函數平均值的最小。
指望風險是模型關於聯合分佈的指望損失,經驗風險是模型關於訓練樣本數據集的平均損失。根據大數定律,當樣本容量N趨於無窮時,經驗風險趨於指望風險。 所以很天然地想到用經驗風險去估計指望風險。可是因爲訓練樣本個數有限,可能會出現過分擬合的問題,即決策函數對於訓練集幾乎所有擬合,可是對於測試集擬合效果過差。所以須要對其進行矯正:
經過公式能夠看出,結構風險:在經驗風險上加上一個正則化項(regularizer),或者叫作罰項(penalty) 。正則化項是J(f)是函數的複雜度再乘一個權重係數(用以權衡經驗風險和複雜度)
2.5最小二乘法
那麼爲了求出這個二次函數的最小值,對其進行求導,導數爲0的時候取得最小值:
進而:
正好是算數平均數(算數平均數是最小二乘法的特例)。 這就是最小二乘法,所謂「二乘」就是平方的意思。 (高斯證實過:若是偏差的分佈是正態分佈,那麼最小二乘法獲得的就是最有可能的值。)
2、簡單線性迴歸實現及向量化應用
python手動實現
import numpy as np class SimpleLinearRegression: def __init__(self): """模型初始化函數""" self.a_ = None self.b_ = None def fit(self, x_train, y_train): """根據訓練數據集x_train,y_train訓練模型""" assert x_train.ndim ==1 '''簡單線性迴歸模型僅可以處理一維特徵向量''' assert len(x_train) == len(y_train) '''特徵向量的長度和標籤的長度相同''' x_mean = np.mean(x_train) y_mean = np.mean(y_train) num = (x_train - x_mean).dot(y_train - y_mean) # 分子 d = (x_train - x_mean).dot(x_train - x_mean) # 分母 self.a_ = num / d self.b_ = y_mean - self.a_ * x_mean return self def predict(self, x_predict): """給定待預測數據集x_predict,返回表示x_predict的結果向量""" assert x_predict.ndim == 1 '''簡單線性迴歸模型僅可以處理一維特徵向量''' assert self.a_ is not None and self.b_ is not None '''先訓練以後才能預測''' return np.array([self._predict(x) for x in x_predict]) def _predict(self, x_single): """給定單個待預測數據x_single,返回x_single的預測結果值""" return self.a_ * x_single + self.b_ def __repr__(self): """返回一個能夠用來表示對象的可打印字符串""" return "SimpleLinearRegression()"
向量化運算:
向量w和向量v,每一個向量的對應項,相乘再相加。其實這就是兩個向量「點乘」
這樣咱們就可使用numpy中的dot運算,很是快速地進行向量化運算。
總的來講:向量化是很是經常使用的加速計算的方式,特別適合深度學習等須要訓練大數據的領域。
對於 y = wx + b, 若 w, x都是向量,那麼,能夠用兩種方式來計算,第一是for循環:
y = 0 for i in range(n): y += w[i]*x[i] y += b
向量化
y = np.dot(w,x) + b
對於獨立的樣本,用for循環串行計算的效率遠遠低於向量化後,用矩陣方式並行計算的效率。所以: 只要有其餘可能,就不要使用顯示for循環。
3、多元線性迴歸:多選線性迴歸和正規方程解及實現
1.經過分析問題,肯定問題的損失函數或者效用函數;
2.而後經過最優化損失函數或者效用函數,得到機器學習的模型。而後咱們推導並實現了最小二乘法,而後實現了簡單線性迴歸。最後還以簡單線性迴歸爲例,學習了線性迴歸的評價指標:均方偏差MSE、均方根偏差RMSE、平均絕對MAE以及R方。
可是,在真實世界中,一個樣本一般有不少(甚至成千上萬)特徵值的,這就是多元線性迴歸。本篇內容咱們學習多元線性迴歸並實現。
對於下面的樣本數據集
對應的是一個向量,每一行是一個樣本,每列對應一個特徵。對應的結果能夠用以下以下公式:
簡單線性迴歸,只計算前兩項,可是在多元線性迴歸中就要學習到n+1個參數,就能求出多元線性迴歸預測值:
也就是:第一個特徵與參數1相乘、第二個特徵與參數2相乘,累加以後再加上截距。就能獲得預測值。 求解思路也與簡單線性迴歸很是一致,目標一樣是:
已知訓練數據樣本X、y ,找到
,使
儘量小.
其中
是列向量列向量,並且咱們注意到,能夠虛構第0個特徵X0,另其恆等於1,推導時結構更整齊,也更加方便:
這樣咱們就能夠改寫成向量點乘的形式:
此時,咱們能夠得出:
所以咱們能夠把目標寫成向量化的形式:
已知訓練數據樣本X、y ,
推導出能夠獲得多元線性迴歸的正規方程解:
固然了,具體的推導過程不須要了解的,不影響咱們的使用,咱們只要知道結果思想就行,結果也不用背下來,在網上搜一下就能找到。
可是這種樸素的計算方法,缺點是時間複雜度較高:O(n^3),在特徵比較多的時候,計算量很大。優勢是不須要對數據進行歸一化處理,原始數據進行計算參數,不存在量綱的問題(多選線性不必作歸一化處理)。
python代碼實現多元線性迴歸:
import numpy as np from sklearn.metrics import r2_score class LinearRegression: def __init__(self): """初始化Linear Regression模型""" self.coef_ = None # 係數(theta0~1 向量) self.interception_ = None # 截距(theta0 數) self._theta = None # 總體計算出的向量theta def fit_normal(self, X_train, y_train): """根據訓練數據X_train,y_train訓練Linear Regression模型""" assert X_train.shape[0] == y_train.shape[0] '''the size of X_train must be equal to the size of y_train''' # 正規化方程求解 X_b = np.hstack([np.ones((len(X_train), 1)), X_train]) self._theta = np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T).dot(y_train) self.interception_ = self._theta[0] self.coef_ = self._theta[1:] return self def predict(self, X_predict): """給定待預測的數據集X_predict,返回表示X_predict的結果向量""" assert self.interception_ is not None and self.coef_ is not None '''must fit before predict''' assert X_predict.shape[1] == len(self.coef_) '''the feature number of X_predict must be equal to X_train''' X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict]) y_predict = X_b.dot(self._theta) return y_predict def score(self, X_test, y_test): """很倔測試機X_test和y_test肯定當前模型的準確率""" y_predict = self.predict( X_test) return r2_score(y_test, y_predict) def __repr__(self): return "LinearRegression()"