线性回归数据_数据科学笔记(三)——线性回归
1. 機器學習眼中的線性回歸
左圖是原始建模數據,目的是用來尋找玩偶數量和成本的某種關系。右圖將數據可視化得到散點圖。
第一步 進行場景確定
第二步 定義損失函數
建模的目的:模型預測值與真實值之間的差距越小越好。下面有兩種定義損失函數的方法。帶“帽子”的變量代表預測值。不帶的表示觀測值。
由于以上兩點原因,所以采用右邊的函數作為損失函數。
實際上使用左面的函數定義損失函數也能得到一個線性模型,只是并不是我們常說的線性回歸模型而已。
所以:損失函數是機器學習模型的核心。(即使相同的模型形式,不同的損失函數對應著不同模型的效果)。
第三步 特征提取
原始數據比較干凈,所以并不需要進行數據清洗。在本題中玩偶個數可以作為特征直接使用。
第四步 確定模型形式和參數估計
第五步 評估模型效果
對于回歸問題,常用的模型評估指標有兩個:
均方差(MSE):預測值與真實值的平均差距。L指的是上面定義的損失函數。
決定系數(R2):數據變化被模型解釋的比例。
第一個公式為成本變化幅度。即真實值與真實值平均值之間的差值的平方和。
第二個公式是未被模型所解釋的變化幅度。即真實值與預測值之間的差值的平方和。從建模的角度來講,我們希望該公式得到的值越小越好。
所以,決定系數的公式如下:結果越接近于1,模型的預測效果越好。
2.? 統計眼中的線性回歸
2.1 模型的假設
在機器學習的角度,我們并不太關心 x 和 y 的數學關系是怎么樣的。整個的建模過程是機械化的。我們只是關心能用什么樣的公式能讓從 x 出發的預測值與真實值 y 之間的關系最小的可以了。
站在統計學的角度出發,我們試圖弄清楚變量 y 與 x 之間的數學關系。
比如 04/01 和 04/02 兩天的玩偶個數都是10,但前者成本為7.7,后者成本為9.87.這說明變量 y?似乎帶有某種隨機性。并且在散點圖中,我們同樣得到 x 與 y 似乎存在某種線性關系。
在上面公式的基礎上,進一步假設。其中假設的 第二點 和 第三點 可能與現實情況沖突。
根據這三個假設我們可以進一步來分析為什么會存在 x 相同而 y 不同的情況。
首先假設模型的?a, b, σ(假設1:隨機擾動項服從的正態分布的方差)是已知的。這時候我們可以看到 y 是由?ax + b + 隨機值?構成,那么就說明 y 本身就是一個隨機值。而且也可以很清楚的證明 yi?是服從 期望為?10a+b?方差為?σ2?的正態分布。所以,有?相同的玩偶個數,不同的成本?這種情況出現正是因為?成本分別是同一正態分布的兩次獨立觀測值。
所以,在統計學的眼里,我們得到的變量值其實是一個隨機變量的觀測值,它并不是一個確定的值。因此,統計學希望通過這樣一個隨機變量的觀測值去挖掘真實的值是多少。
2.2 參數估計公式(最大似然估計法 Maximum Likelihood Estimation, MLE)
根據上面的模型假設,可以得到:
由于 y 是隨機變量,就可以定義參數的似然函數(Likelihood function):
這里的似然函數 L 其實就是 y 的聯合條件概率。并且 yi?是相互獨立的,那么就可以將似然函數 L 改寫成每一點概率的乘積的形式。這一點可以極大地方便后面的數學處理。
既然 y 是隨機變量,那么模型參數估計的原則就是?y出現的概率達到最大。
這就是所謂的?最大似然估計法(Maximum Likelihood Estimation, MLE)。
2.3 最大似然估計法與機器學習模型參數估計公式的關系
在機器學習中,首先定義了損失函數,也就是模型真實值與預測值之間的差距。
在機器學習中,參數估計的原則就是使?損失函數達到最小值。
而在統計學中,我們從 y 是隨機變量這一點出發,參數估計的原則就是使?y出現的概率達到最大。
將統計學中的最大似然估計法翻譯成公式:
由于 L 這里是乘積的形式:
? 那么為了數學上好處理,引入自然對數函數,也就是以 e為底(2.71828...)的對數函數。對于它有以下性質:
同時,我們也注意到自然對數函數本身是一個增函數,也就是說 L 達到最大值的時候 ln(L) 也達到最大值,因此可以把尋找參數 a, b 的公式改寫為:
? 從之前已經證明 yi?服從正態分布,因此將 lnL 展開,得到如下的式子:
我們可以注意到 前面(一個紅線)是一個固定的值,后面(兩個紅線)才是變量。如果我們想要 lnL 達到最大值,那么我們就要后面的變量達到最小值。所以最終的參數估計公式也就變成了:
這就與前面機器學習里面的?線性回歸模型(最小二乘法OLS)的參數估計公式相同。
在之前機器學習的討論中,我們知道?只要定義一種不同的損失函數,就有一種新的線性回歸模型。那么為什么我們通常使用的就是 最小二乘法(OLS)線性回歸模型呢?
就是因為它使用的損失函數背后有極為強大的數學基礎。
由于 最大似然估計法 與 OLS線性回歸模型 的參數估計公式是相同的,所以它們得到的結果是一樣的。
2.4 置信區間
根據 2.3 的討論,我們有了模型參數估計值的公式:
根據模型參數估計公式,可以得到參數 a, b 的估計值。但是,使用不同數據訓練模型的時候,會得到不同的參數估計值。(這里的不同的數據,指的是符合同一規律的數據)。
例如:我們采用 04/01,04/02,04/03 和 04/04,04/05,04/06 日期的數據分別訓練模型可得到兩個估計值,而且這兩個值是不相同的:
這是因為?模型參數的估計值只是一個隨機變量,具體數值依賴于使用的數據。而且數學上可以證明,參數估計值本身是隨機變量,并且服從正態分布。
數學上的證明較為繁瑣,所以這里就采用一個實證的例子:
既然得到的估計值只是隨機變量的一次觀測值,那么我們更關心這個估計值離真實值有多遠?
在統計學里,解決方案就是?定義參數真實值的置信區間。
在上面的證明,我們可以得知估計值服從以真實值為期望的正態分布。參數的真實值就是 a 。我們假設這個正態分布的方差為σ2,那么大部分估計值就會落在以 真實值a 為中心,2倍 σ 為半徑的區間里面。
將其翻譯為數學公式,即為:
因此,可以定義參數 a 的 95% 的置信區間:
所以,95%的置信區間表示:
重復100次的模型訓練,并按公式得到置信區間,那么有95次,參數 a 的真實值將落在這個區間里。
也可以 “通俗地” 理解為參數 a 的大概取值范圍。
后面一句話其實不太嚴謹,因為一開始 假設 參數 a 的真實值是一個確定的值,但是現在又說大概的范圍,這又將參數 a 作為一個隨機值進行處理,這前后是矛盾的。不過,依然可以這樣通俗的進行理解。
置信區間就是控制模型結果隨機性的一個工具。也就是說我們得到的參數的估計值其實是一個隨機變量。它并不等于真實值,但是我們可以用置信區間去控制這個真實值大概所在的區間范圍是多少。
2.5 假設檢驗
除了置信區間外,還可以使用假設檢驗來得到更有把握的結果。
具體來說,我們剛剛得到了 a 的估計值,但是我們不知道 a 的真實值是多少。那么我們可以做一個假設,比如我們假設 a = 0 。那么根據這個假設,以及 a 的估計值服從正態分布,那么我們可以得到在 a = 0 的情況下,也就是在這個假設成立的條件下,估計值大致分布的區間也就是 0-2σ 到 0+2σ。
這時,我們得到模型估計值是 0.98 。它沒有落在大致分布的區間內,這是概率很小的事情。那么在這個情況下,我們就可以拒絕之前的假設 a = 0。因為在這個假設成立的條件下,幾乎不可能的事情發生了。
換個角度來看,使用剛剛定義的置信區間,我們得到 0 并沒有在置信區間內,根據這個我們也可以拒絕 a = 0? 這樣的一個假設。
總結一下:
1. 對于單個參數的假設檢驗與置信區間比較類似,二者相通。
2. 也可以對多個參數做組合的假設檢驗。
3. 模型陷阱(過擬合與模型幻覺)
3.1 模型陷阱概述
在現實生活中,搭建模型主要有兩種用途。
1. 正向運用:對未知情況做預測。(也就是知道 x1, x2, x3.....對 y 值進行預測)
要求準確度很高,得到的 y 越接近真實值越好。
易受到過度擬合干擾。
2. 反向運用:解釋數據之間的聯動效應。(也就是目標值 y 與什么變量有關)
數據驅動的本質。不是特別關心模型的準確性,而是關心模型的可靠性。
易受到模型幻覺干擾。(也就是誤以為某個 x 與最終值 y 是有關系的)
過度擬合?和?模型幻覺?統稱為?模型陷阱。
3.2 過度擬合
同樣以 y=x 為真實的模型結果為例。隨著模型更加復雜,均方差和決定系數確實是向更好的方向進行發展。但是實際上我們知道模型就是最簡單的 y=x 線性模型。這里就是一個悖論,我們使用評估模型的指標并沒有挑選出更真實的模型,這就是所謂的過度擬合。
對于過度擬合來說
1. 對于已知數據,模型越復雜 “效果越好”。
這里有一個既當運動員又當裁判員的問題。歷史數據我們用來搭建模型,但也使用它來對模型的效果進行評估,這是導致這個問題的原因。
2. 模型的擴展性非常差。
如果我們使用后面三幅圖的模型進行預測,那么結果是非常不準確的。
解決方法分為兩類:
1. 數據層面
在現實生活中,模型的使用周期如下圖
由于我們的目的是為了預測未知數據,所以我們可以把歷史數據集分為兩份。一份是訓練集,一份是測試集。首先使用訓練集估計模型的參數,然后采用測試集評估模型效果。
通過這種辦法,就可以把部分歷史數據當成了未知數據。
2. 模型層面
模型層面的解決方法:奧卡姆剃刀原則。
對于訓練集來說,通常模型越復雜,結果的誤差也就越小(如下圖 藍線)。但對于測試集來說,當模型太復雜通常會遇到?過度擬合?的現象,當模型太簡單會遇到?欠擬合?的現象,這兩種現象誤差都會很大。
我們的目的是選擇?剛剛好的模型復雜程度使得在測試集上的誤差達到最小。
但在現實中,最佳選擇是非常難實現的。這時候有一個很好的解決辦法,就是奧卡姆剃刀原則。
Occam's Razor: 如無必要,切勿假定繁多。
這句話的意思是,如果兩個模型對于未知數據的預測結果差不多的時候,應該選擇更加簡單的那個模型。
3.3 機器學習對于模型幻覺的解決方法(懲罰項 L1,L2范數及網格搜尋)
在現實中,控制模型復雜程度的方法主要有兩種:
1. 模型本身的復雜度。(比如 線性回歸 比 神經網絡 更簡單)。
2. 模型使用的特征,包括個數以及特征的復雜度。( x 的個數)
第二種方法實現起來更加容易,但是會引起 模型幻覺。
模型幻覺 指?不相關的特征?被加入到模型里,且被認為與預測結果有相關性。
3.3.1 懲罰項
回顧一下使用的數據,x 指的是玩偶個數,y 指的是生產成本。他們之間的關系是?y = x + 一個隨機變量
這時我們引入一個不相關的變量 z,但是這里假設我們不知道它是無關的。這時的方程就變成了
y = ax + bz + c
但是其實在這個模型里參數 b 和 c的真實值都為 0 。
根據之前的討論,可以定義 y = ax + bz + c 的損失函數。在 損失函數L 中我們希望 讓真實值等于 0 的 b,c 盡可能的靠近 0 。
解決方案就是?加入懲罰項?。加入懲罰項后,a, b, c 的值越遠離 0 ,損失函數 L 的值也就越大。這就使得模型的參數盡可能的靠近 0 。從另外一個角度來說,如果 b 的估計值為 0 ,這相當于在模型里沒有使用變量 z 通過這種方式,自動地限制了模型的復雜程度。在理想情況下,無論參數 b 的值是多少,都不會影響原損失函數的取值,因此這樣的一個公式會使?不相關的 b 和 c 靠近 0?, 而不是讓 a 靠近 0 。
其中?α 被稱為懲罰力度。
上面的懲罰項被稱為?L1懲罰項(L1 范數),如果加入了 L1懲罰項,整個模型就被稱為?Lasso回歸。
下面的懲罰項被稱為?L2懲罰項(L2 范數),如果加入了 L2懲罰項,整個模型就被稱為?Ridge回歸。
3.3.2 網格搜尋
首先,看看增加懲罰項后,模型的結果有什么變化。我們可以看出懲罰力度 α 越大,b 和 c 的估計值越靠近于 0 ,a 的值就越靠近于 1 。三者越來越靠近它的真實值。但是這不意味著 懲罰力度?α 總是越大越好。那該如何選擇?懲罰力度?α?呢??
這里需要注意的是,對于 a, b, c 是有數學公式來求最優值的。但是 懲罰力度?α 是沒有的。能想到的辦法就只有?網格搜尋,也就是一種遍歷的辦法。給定一些 α 的備選值分別去訓練模型。最后選擇技術指標最好的 α 作為最終的 α 。
總結一下,機器學習對于模型幻覺的解決辦法。這里還有一個問題,如果模型有超參數,那么測試集也出現了既當裁判員又當運動員的問題。即超參數選擇和測試指標都用了測試集。這時候就將數據分成三個集合 訓練集,驗證集,測試集。這樣就解決了這個問題。
a,b,c 是模型的參數,懲罰力度?α 是模型的超參數。
3.4 統計分析的解決方法(假設檢驗)
模型的式子是 y = ax + bz + c,在圖片中我們可以得到?b,c的估計值都不等于0,但是根據后面的結果,我們可以得到?b,c都不顯著。換句話說,并不能拒絕 b,c 的真實值等于0的假設。換個角度看,在 b,c 的95%置信區間內都包含了0,所以依然并不能拒絕 b,c 的真實值等于0的假設。所以才實際操作中,如果模型的參數不顯著,就可以將其排除。因此?將變量 z 排除出模型,重新建模。參數 c 被稱為截距項,是一個特殊的參數,這里并不排除。
3.5 機器學習和統計解決模型幻覺的方法比較
機器學習雖然使無關變量前面的系數盡可能接近于 0 ,但是仍未能完全排除。而統計分析可以將無關的變量完全排除出模型。但這就說明統計分析需要更多的人為干預,是否排除無關變量是一個人為的選擇,隨意性較大。(具體是多少的顯著度是沒辦法量化的,比如 顯著度5%還是1% 就認為不顯著)。
目的在于預測,可以采用機器學習方法。目的在于分析 y 和 x 之間的關系,盡可能使用統計方法。
4. 模型的生命周期
模型的一生分為兩個階段。一是模型的訓練(下圖虛線以下部分),二是模型的使用(下圖虛線以上部分)。
連接這兩個階段的IT工具就是模型的保存和讀取。
如果訓練模型和使用模型都是 Python 程序,則可以使用 pickle 來實現模型的持久化(保存和讀取)。
pickle 是 Python 的一個標準模塊,它可以將 Python 對象保存為文件,也可以從保存文件里還原相應的 Python 對象。
如果訓練模型和使用模型分別使用兩種不同的語言,則可以使用 PMML 來實現模型在不同編程語言之間的保存和讀取。
PMML 是一種描述預測模型的標準,它與使用的編程語言無關。
PMML 主要記錄三類信息:模型類別、模型變量、模型參數。
# -*- coding: UTF-8 -*-"""此腳本用于展示使用sklearn搭建線性回歸模型"""import osimport sysimport numpy as npimport matplotlib.pyplot as pltimport pandas as pdfrom sklearn import linear_modeldef evaluateModel(model, testData, features, labels): """ 計算線性模型的均方差和決定系數 參數 ---- model : LinearRegression, 訓練完成的線性模型 testData : DataFrame,測試數據 features : list[str],特征名列表 labels : list[str],標簽名列表 返回 ---- error : np.float64,均方差 score : np.float64,決定系數 """ # 均方差(The mean squared error),均方差越小越好 error = np.mean( (model.predict(testData[features]) - testData[labels]) ** 2) # 決定系數(Coefficient of determination),決定系數越接近1越好 score = model.score(testData[features], testData[labels]) return error, scoredef visualizeModel(model, data, features, labels, error, score): """ 模型可視化 """ # 為在Matplotlib中顯示中文,設置特殊字體 plt.rcParams['font.sans-serif']=['SimHei'] # 創建一個圖形框 fig = plt.figure(figsize=(6, 6), dpi=80) # 在圖形框里只畫一幅圖 ax = fig.add_subplot(111) # 在Matplotlib中顯示中文,需要使用unicode # 在Python3中,str不需要decode if sys.version_info[0] == 3: ax.set_title(u'%s' % "線性回歸示例") else: ax.set_title(u'%s' % "線性回歸示例".decode("utf-8")) ax.set_xlabel('$x$') ax.set_ylabel('$y$') # 畫點圖,用藍色圓點表示原始數據 # 在Python3中,str不需要decode if sys.version_info[0] == 3: ax.scatter(data[features], data[labels], color='b', label=u'%s: $y = x + \epsilon$' % "真實值") else: ax.scatter(data[features], data[labels], color='b', label=u'%s: $y = x + \epsilon$' % "真實值".decode("utf-8")) # 根據截距的正負,打印不同的標簽 if model.intercept_ > 0: # 畫線圖,用紅色線條表示模型結果 # 在Python3中,str不需要decode if sys.version_info[0] == 3: ax.plot(data[features], model.predict(data[features]), color='r', label=u'%s: $y = %.3fx$ + %.3f'\ % ("預測值", model.coef_, model.intercept_)) else: ax.plot(data[features], model.predict(data[features]), color='r', label=u'%s: $y = %.3fx$ + %.3f'\ % ("預測值".decode("utf-8"), model.coef_, model.intercept_)) else: # 在Python3中,str不需要decode if sys.version_info[0] == 3: ax.plot(data[features], model.predict(data[features]), color='r', label=u'%s: $y = %.3fx$ - %.3f'\ % ("預測值", model.coef_, abs(model.intercept_))) else: ax.plot(data[features], model.predict(data[features]), color='r', label=u'%s: $y = %.3fx$ - %.3f'\ % ("預測值".decode("utf-8"), model.coef_, abs(model.intercept_))) legend = plt.legend(shadow=True) legend.get_frame().set_facecolor('#6F93AE') # 顯示均方差和決定系數 # 在Python3中,str不需要decode if sys.version_info[0] == 3: ax.text(0.99, 0.01, u'%s%.3f\n%s%.3f'\ % ("均方差:", error, "決定系數:", score), style='italic', verticalalignment='bottom', horizontalalignment='right', transform=ax.transAxes, color='m', fontsize=13) else: ax.text(0.99, 0.01, u'%s%.3f\n%s%.3f'\ % ("均方差:".decode("utf-8"), error, "決定系數:".decode("utf-8"), score), style='italic', verticalalignment='bottom', horizontalalignment='right', transform=ax.transAxes, color='m', fontsize=13) # 展示上面所畫的圖片。圖片將阻斷程序的運行,直至所有的圖片被關閉 # 在Python shell里面,可以設置參數"block=False",使阻斷失效。 plt.show()def trainModel(trainData, features, labels): """ 利用訓練數據,估計模型參數 參數 ---- trainData : DataFrame,訓練數據集,包含特征和標簽 features : 特征名列表 labels : 標簽名列表 返回 ---- model : LinearRegression, 訓練好的線性模型 """ # 創建一個線性回歸模型 model = linear_model.LinearRegression() # 訓練模型,估計模型參數 model.fit(trainData[features], trainData[labels]) return modeldef linearModel(data): """ 線性回歸模型建模步驟展示 參數 ---- data : DataFrame,建模數據 """ features = ["x"] labels = ["y"] # 劃分訓練集和測試集 trainData = data[:15] testData = data[15:] # 產生并訓練模型 model = trainModel(trainData, features, labels) # 評價模型效果 error, score = evaluateModel(model, testData, features, labels) # 圖形化模型結果 visualizeModel(model, data, features, labels, error, score)def readData(path): """ 使用pandas讀取數據 """ data = pd.read_csv(path) return dataif __name__ == "__main__": homePath = os.path.dirname(os.path.abspath(__file__)) # Windows下的存儲路徑與Linux并不相同 if os.name == "nt": dataPath = "%s\\data\\simple_example.csv" % homePath else: dataPath = "%s/data/simple_example.csv" % homePath data = readData(dataPath) linearModel(data)"""此腳本用于如何使用統計方法解決模型幻覺"""# 保證腳本與Python3兼容from __future__ import print_functionimport osimport numpy as npimport statsmodels.api as smimport matplotlib.pyplot as pltimport pandas as pddef generateRandomVar(): """ """ np.random.seed(4873) return np.random.randint(2, size=20) def evaluateModel(res): """ 分析線性回歸模型的統計性質 """ # 整體統計分析結果 print(res.summary()) # 用f test檢測x對應的系數a是否顯著 print("檢驗假設z的系數等于0:") print(res.f_test("z=0")) # 用f test檢測常量b是否顯著 print("檢測假設const的系數等于0:") print(res.f_test("const=0")) # 用f test檢測a=1, b=0同時成立的顯著性 print("檢測假設z和const的系數同時等于0:") print(res.f_test(["z=0", "const=0"]))def trainModel(X, Y): """ 訓練模型 """ model = sm.OLS(Y, X) res = model.fit() return resdef confidenceInterval(data): """ """ features = ["x"] labels = ["y"] Y = data[labels] _X = data[features] # 加入新的隨機變量,次變量的系數應為0 _X["z"] = generateRandomVar() # 加入常量變量 X = sm.add_constant(_X) res = trainModel(X, Y) evaluateModel(res) def generateData(): """ 生成模型數據 """ np.random.seed(5320) x = np.array(range(0, 20)) / 2 error = np.round(np.random.randn(20), 2) y = 0.05 * x + error # 新加入的無關變量z恒等于1 z = np.zeros(20) + 1 return pd.DataFrame({"x": x, "z": z, "y": y})def wrongCoef(): """ 由于新變量的加入,正效應變為負效應 """ features = ["x", "z"] labels = ["y"] data = generateData() X = data[features] Y = data[labels] # 沒有多余變量時,x系數符號估計正確,為正 model = sm.OLS(Y, X["x"]) res = model.fit() print("沒有加入新變量時:") print(res.summary()) # 加入多余變量時,x系數符號估計錯誤,為負 model1 = sm.OLS(Y, X) res1 = model1.fit() print("加入新變量后:") print(res1.summary())def readData(path): """ 使用pandas讀取數據 """ data = pd.read_csv(path) return dataif __name__ == "__main__": homePath = os.path.dirname(os.path.abspath(__file__)) # Windows下的存儲路徑與Linux并不相同 if os.name == "nt": dataPath = "%s\\data\\simple_example.csv" % homePath else: dataPath = "%s/data/simple_example.csv" % homePath data = readData(dataPath) print("***************************************************") # 在Windows下運行此腳本需確保Windows下的命令提示符(cmd)能顯示中文 print("加入不相關的新變量,新變量的系數被錯誤估計為不等于0") print("***************************************************") confidenceInterval(data) print("**********************************************") print("加入不相關的新變量,舊變量系數的符號被錯誤估計") print("**********************************************") wrongCoef()參考資料:
1、《精通數據科學:從線性回歸到深度學習》
2、https://www.cnblogs.com/xzt6/p/13379038.html
總結
以上是生活随笔為你收集整理的线性回归数据_数据科学笔记(三)——线性回归的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python连接spark_python
- 下一篇: 动词ing基本用法_动词ing形式的用法