一、線性模型基本概念
?線性模型不是指某一個模型,而是一類模型。在機器學習領域,常用的線性模型包括,線性回歸、嶺回歸、套索回歸、邏輯回歸和線性SVC等。
1.線性模型的圖形表示——擬合兩點
?假設有兩個點(1,3)和(4,5),用python計算出穿過兩點的直線方程,并畫出圖形。
#求解穿過點的直線方程,并繪圖
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression #導入線性回歸模型
#輸入兩點的橫坐標
X = [[1], [4]]
#輸入兩點的縱坐標
y = [3, 5]
#用線性模型擬合這兩個點
lr = LinearRegression().fit(X, y)
#畫出兩個點和直線圖形
z = np.linspace(0, 5, 20)
plt.scatter(X, y, s=80)
plt.plot(z, lr.predict(z.reshape(-1, 1), c='k'))
#設定圖片標題
plt.title('Straight Line')
#輸出直線方程
print('直線方程為:')
print('==========================')
print('y = {:.3f}'.format(lr.coef_[0]), 'x',' + {:.3f}'.format(lr.intercept_))
plt.show()
執行結果如下,直線穿過兩個點:
直線方程為:
==========================
y = 0.667 x + 2.333
注釋1:
numpy.linspace 用來生成等差數列
函數原型:numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0)
參數解釋:
?start:返回樣本數據開始點
?stop:返回樣本數據結束點
?num:生成的樣本數據量,默認為50
?endpoint:True則包含stop;False則不包含stop
?retstep:If True, return (samples, step), where step is the spacing between samples.(即如果為True則結果會給出數據間隔)
?dtype:輸出數組類型
?axis:0(默認)或-1
返回類型:
Return evenly spaced numbers over a specified interval.
(在start和stop之間返回均勻間隔的數據)
Returns num evenly spaced samples, calculated over the interval [start, stop].
(返回的是 [start, stop]之間的均勻分布)
The endpoint of the interval can optionally be excluded.
Changed in version 1.16.0: Non-scalar start and stop are now supported.
(可以選擇是否排除間隔的終點)
注釋2:
reshape(行,列) 可以根據指定的數值將數據轉換為特定的行數和列數,就是轉換成矩陣。
如果 reshape(-1,1)或者 reshape(1,-1)意味著轉換成為一列或者一行
注釋3:
sklearn.linear_model.LogisticRegression
函數原型:sklearn.linear_model.LogisticRegression(penalty=’l2’, dual=False, tol=0.0001, C=1.0, fit_intercept=True, intercept_scaling=1, class_weight=None, random_state=None, solver=’liblinear’, max_iter=100, multi_class=’ovr’, verbose=0, warm_start=False, n_jobs=1)
參數解釋:
?penalty: 一個字符串,指定了正則化策略。可選 l2 、l1
?dual : 一個布爾值。如果為True,則求解對偶形式(只在penalty=‘l2’且solver=‘liblinear’有對偶形式),如果為False,則求解原始形式。
?C : 一個浮點數。它指定了罰項系數的倒數。如果它的值越小,則正則化項越大。
?fit_intercept : 一個布爾值,指定是否需要計算b值。如果為False,那么不計算b值。
?intercept_scaling : 一個浮點數。只有當solver=‘liblinear’才有意義。當采用fit_intercept時,相當于人造了一個特征,該特征恒為1,其權重為b。在計算正則化項的時候,該人造特征也被考慮了。因此為了降低這個人造特征的影響,需要提供intercept_scaling。
?class_weight : 一個字典或者字符串‘balanced’。
??? ?字典 : 字典給出每個分類的權重。
????balanced : 每個分類的權重與該分類在樣本集中出現的頻率成反比。
未指定 : 每個分類權重都為1。
?max_iter : 一個整數,制定最大迭代數。
?random_state :一個整數或者一個RandomState實例,或者None。
整數,則指定了隨機數生成器的種子。
????RandomState,則指定了隨機數生成器。
????None,則默認使用隨機數生成器。
?solver : 一個字符串,指定了求解最優化的算法,可以為:
????newton-cg : 使用牛頓法。只適用于penalty=‘l2’。
????lbfgs : 使用L-BFGS擬牛頓法。只適用于penalty=‘l2’。
????liblinear : 使用liblinear,適用于小數據集。
????sag : 使用Stochastic Average Gradient Descent算法,適用于大數據集。只適用于penalty=‘l2’。
?tol : 一個浮點數,指定判斷迭代收斂與否的閾值
?multi_class : 一個字符串,指定對于多分類問題的策略,可以為:
????ovr : 采用one-vs-rest策略。
????multinomial : 直接采用多分類邏輯回歸策略,不能與liblinear共存。
?verbose : 一個正數。用于開啟關閉迭代中輸出日志。
?warm_start: 一個布爾值。如果為True,那么使用前一次訓練結果繼續訓練。否則從頭開始訓練
?n_jobs : 一個正數。任務并行時指定的CPU數量。如果為-1則使用所有可用的CPU。
返回類型:
coef_ : 權重向量。
intercept_ :b值。
n_iter :實際迭代次數。
2.線性模型的圖形表示——擬合三點
?再增加一個點(3, 3)再看結果
#求解穿過點的直線方程,并繪圖
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression #導入線性回歸模型
#輸入兩點的橫坐標
#X = [[1], [4]]
#輸入兩點的縱坐標
#y = [3, 5]
#輸入三點的橫坐標
X = [[1], [4], [3]]
#輸入三點的縱坐標
y = [3, 5, 3]
#用線性模型擬合輸入點
lr = LinearRegression().fit(X, y)
#畫出點和直線圖形
z = np.linspace(0, 5, 20)
plt.scatter(X, y, s=80)
plt.plot(z, lr.predict(z.reshape(-1, 1)), c='k')
#設定圖片標題
plt.title('Straight Line')
#輸出直線方程
print('直線方程為:')
print('==========================')
print('y = {:.3f}'.format(lr.coef_[0]), 'x',' + {:.3f}'.format(lr.intercept_))
plt.show()
執行結果如下,直線未穿過三個點,但是位于一個和3個點距離相加最小的位置:
直線方程為:
==========================
y = 0.571 x + 2.143
3.線性模型的圖形表示——擬合多點
?使用scikit-learn 生成的 make_regression 數據集
#求解穿過多點的直線方程,并繪圖
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_regression #回歸分析數據生成器
from sklearn.linear_model import LinearRegression #導入線性回歸模型
#生成用于回歸分析的數據集
X, y = make_regression(n_samples=50, n_features=1, n_informative=1, noise=50, random_state=1)
#使用線性模型對數據進行擬合
reg = LinearRegression()
reg.fit(X, y)
#z是生成的等差數列,用來畫出模型的預測結果圖形
z = np.linspace(-3, 3, 200).reshape(-1, 1)
plt.scatter(X, y, c='b', s=60)
plt.plot(z, reg.predict(z), c='k')
print('直線方程為:')
print('==========================')
print('y = {:.3f}'.format(reg.coef_[0]), 'x',' + {:.3f}'.format(reg.intercept_))
print('直線的斜率為:{:.2f}'.format(reg.coef_[0]))
print('直線的截距為:{:.2f}'.format(reg.intercept_))
plt.show()
執行結果如下:
直線方程為:
==========================
y = 79.525 x + 10.922
直線的斜率為:79.52
直線的截距為:10.92
注釋:
sklearn.datasets.make_regression
函數原型:sklearn.datasets.make_regression(_samples=100, n_features=100, n_informative=10,
n_targets=1, bias=0.0, effective_rank=None,
tail_strength=0.5, noise=0.0, shuffle=True, coef=False,
random_state=None)關鍵參數解釋:
?n_samples(生成樣本數)
?n_features(樣本特征數)
?noise(樣本隨機噪音)
?coef(是否返回回歸系數)返回類型:
?X為樣本特征
?y為樣本輸出
?coef為回歸系數
二、基本的線性模型——線性回歸
?線性回歸,也稱為最小二乘法(OLS)。基于預測值很真實值的均方誤差最小化來進行模型求解的方法稱為“最小二乘法”。在線性回歸中,最小二乘法就是試圖找到一條直線,使所有樣本到直線上的歐式距離之和最小。線性回歸沒有可供用戶調節的參數。這意味著,模型的復雜度不可控。
?使用糖尿病數據集進行演示.
#線性回歸
#線性回歸
from sklearn.datasets import load_diabetes #載入糖尿病數據
from sklearn.linear_model import LinearRegression #導入線性回歸模型
from sklearn.model_selection import train_test_split #切分訓練集和測試集
X, y = load_diabetes().data, load_diabetes().target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=8)
lr = LinearRegression().fit(X_train, y_train)
print('代碼運行結果為:')
print('==========================')
print('lr.coef_為:{}'.format(lr.coef_))
print('lr.intercept_為:{}'.format(lr.intercept_))
print('\n')
print('回歸方程為:')
print('==========================')
print('y = {:.3f}'.format(lr.coef_[0]), '*x1 + {:.3f}'.format(lr.coef_[1]), '*x2' ,' + ({})'.format(lr.intercept_))
print('\n')
print('==========================')
print("訓練數據得分:{:.2f}".format(lr.score(X_train, y_train)))
print("測試數據得分:{:.2f}".format(lr.score(X_test, y_test)))
執行結果如下:
代碼運行結果為:
==========================
lr.coef_為:[ 11.5106203 -282.51347161 534.20455671 401.73142674 -1043.89718398
634.92464089 186.43262636 204.93373199 762.47149733 91.9460394 ]
lr.intercept_為:152.5624877455247
回歸方程為:
==========================
y = 11.511 *x1 + -282.513 *x2 + (152.5624877455247)
==========================
訓練數據得分:0.53
測試數據得分:0.46
結果顯示得分很低,也就是模型在實際數據中效果不好,出現了過擬合現象,因此,需要對線性回歸模型就行正則化,使得可以控制模型的復雜度。
2.1、使用L2正則化的線性模型——嶺回歸
?嶺回歸是一種改良的最小二乘法。可以避免過擬合。在嶺回歸中,模型會保留所有的特征變量,但是會減小特征變量的系數值,讓特征變量對預測結果的影響變小,在嶺回歸中是通過改變其alpha參數來控制減小特征變量系數的程度。而這種通過保留全部特征變量,只是降低特征變量的系數值來避免過擬合的方法,成為L2正則化。
?在嶺回歸中。是通過linear_model.Ridge函數來調用的。以糖尿病為例,并對比不同alpha值和線性回歸模型下,模型的coef_屬性值。
from sklearn.linear_model import Ridge #導入嶺回歸
from sklearn.linear_model import LinearRegression #導入線性回歸模型
from sklearn.datasets import load_diabetes #載入糖尿病數據
from sklearn.model_selection import train_test_split #切分訓練集和測試集
import matplotlib.pyplot as plt
X, y = load_diabetes().data, load_diabetes().target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=8)
lr = LinearRegression().fit(X_train, y_train)
#取不同的 alpha 來看參數對結果的影響
ridge1 = Ridge(alpha=1).fit(X_train, y_train)
ridge10 = Ridge(alpha=10).fit(X_train, y_train)
ridge01 = Ridge(alpha=0.1).fit(X_train, y_train)
print('代碼運行結果為:')
print('==========================')
print("訓練數據得分:{:.2f}".format(ridge10.score(X_train, y_train)))
print("測試數據得分:{:.2f}".format(ridge10.score(X_test, y_test)))
#繪制 線性模型系數
plt.plot(lr.coef_, 'o', label = 'LinearRegression')
#繪制 alpha = 0.1 時的模型系數
plt.plot(ridge01.coef_, 's', label = 'Ridge alpha=0.1')
#繪制 alpha = 1 時的模型系數
plt.plot(ridge1.coef_, '^', label = 'Ridge alpha=1')
#繪制 alpha = 10 時的模型系數
plt.plot(ridge10.coef_, 'v', label = 'Ridge alpha=10')
plt.xlabel("coefficient index 系數序號")
plt.ylabel("coeffient magniutde 系數量級")
plt.hlines(0, 0, len(lr.coef_))
plt.legend()
plt.show()
運行結果為:
圖中。橫軸為coef_屬性,縱軸為特征變量的系數量級。從圖中可以看出,當 alpha = 10 時,特征變量系數大多在0附近;當 alpha = 1時,嶺回歸的特征變量系數明顯增大;;當 alpha = 0.1 時,嶺回歸的特征變量系數更大,甚至于線性回歸模型的點重合了。
?另外一個理解正則化對模型的影響的方法,就取一個固定的alpha值,然后改變訓練集的數據量,得到一個隨數據集大小而不斷改變的模型評分折線圖,具體代碼如下:
import numpy as np
from sklearn.linear_model import Ridge #導入嶺回歸
from sklearn.linear_model import LinearRegression #導入線性回歸模型
from sklearn.datasets import load_diabetes #載入糖尿病數據
from sklearn.model_selection import train_test_split #切分訓練集和測試集
from sklearn.model_selection import learning_curve,KFold
import matplotlib.pyplot as plt
X, y = load_diabetes().data, load_diabetes().target
#定義一個繪制折線圖的函數
def plot_learning_curve(est, X, y):
training_set_size, train_scores, test_scores = learning_curve(est, X, y, train_sizes=np.linspace(.1, 1, 20),
cv=KFold(20, shuffle=True, random_state=1))
estimator_name = est.__class__.__name__
line = plt.plot(training_set_size, train_scores.mean(axis=1), '--', label="training "+ estimator_name)
plt.plot(training_set_size, test_scores.mean(axis=1), '--', label="test "+ estimator_name, c=line[0].get_color())
plt.xlabel('Trainint set size')
plt.ylabel('Score')
plt.ylim(0, 1.1)
plot_learning_curve(Ridge(alpha=1), X, y)
plot_learning_curve(LinearRegression(), X, y)
plt.legend(loc=(0, 1.05), ncol=2, fontsize=11)
plt.show()
執行結果如下:
?從圖上可以看出,由于嶺回歸模型是進過正則化的模型,因此它在整個圖像中訓練數據及的得分比線性回歸的低,但是嶺回歸的測試數據集得分和訓練數據集得分差異小。隨著數據集的增加,如果有足夠多的數據,那么正則化就沒那么重要了,嶺回歸和線性回歸的表現相差無幾。
注釋1:
sklearn.model_selection.learning_curve
函數原型:sklearn.model_selection.learning_curve(estimator, X, y, groups=None, train_sizes=array([0.1, 0.33, 0.55, 0.78, 1. ]), cv=’warn’, scoring=None, exploit_incremental_learning=False, n_jobs=None, pre_dispatch=’all’, verbose=0, shuffle=False, random_state=None, error_score=’raise-deprecating’)
關鍵參數解釋:
?estimator:實現“ fit”和“ predict”方法的對象類型。每次驗證都會克隆的該類型的對象。
?X:數組類,形狀(n_samples,n_features)。訓練向量,其中n_samples是樣本數,n_??features是特征數。
?y:數組類,形狀(n_samples)或(n_samples,n_features),可選。相對于X的目標進行分類或回歸;無監督學習無。
?groups:數組類,形狀為(n_samples,),可選。將數據集拆分為訓練/測試集時使用的樣本的標簽分組。僅用于連接交叉驗證實例組(例如GroupKFold)。
?train_sizes:數組類,形狀(n_ticks),dtype float或int。訓練示例的相對或絕對數量,將用于生成學習曲線。如果dtype為float,則視為訓練集最大尺寸的一部分(由所選的驗證方法確定),即,它必須在(0,1]之內,否則將被解釋為絕對大小注意,為了進行分類,樣本的數量通常必須足夠大,以包含每個類中的至少一個樣本(默認值:np.linspace(0.1,1.0,5))
?cv:int,交叉驗證生成器或可迭代的,可選的.確定交叉驗證拆分策略。cv的可能輸入是:
?? None,要使用默認的三折交叉驗證(v0.22版本中將改為五折)
?? 整數,用于指定(分層)KFold中的折疊數,
?? CV splitter
?? 可迭代的集(訓練,測試)拆分為索引數組。
?? 對于整數/無輸入,如果估計器是分類器,y是二進制或多類,則使用StratifiedKFold。在所有其他情況下,都使用KFold。
?scoring:字符串,可調用或無,可選,默認:None。字符串(參閱model evaluation documentation)或帶有簽名scorer(estimator, X, y)的計分器可調用對象/函數。
?exploit_incremental_learning:布爾值,可選,默認值:False. 如果估算器支持增量學習,此參數將用于加快擬合不同訓練集大小的速度。
?n_jobs:int或None,可選(默認=None)。要并行運行的作業數。None表示1。 -1表示使用所有處理器。有關更多詳細信息,請參見詞匯表。
?pre_dispatch:整數或字符串,可選。并行執行的預調度作業數(默認為全部)。該選項可以減少分配的內存。該字符串可以是“ 2 * n_jobs”之類的表達式。
?verbose:整數,可選。控制詳細程度:越高,消息越多。
?shuffle:布爾值,可選。是否在基于``train_sizes’'為前綴之前對訓練數據進行洗牌。
?random_state:int,RandomState實例或無,可選(默認=None)。如果為int,則random_state是隨機數生成器使用的種子;否則為false。如果是RandomState實例,則random_state是隨機數生成器;如果為None,則隨機數生成器是np.random使用的RandomState實例。在shuffle為True時使用。
?error_score:‘raise’ | ‘raise-deprecating’ 或數字。如果估算器擬合中出現錯誤,則分配給分數的值。如果設置為“ raise”,則會引發錯誤。如果設置為“raise-deprecating”,則會在出現錯誤之前打印FutureWarning。如果給出數值,則引發FitFailedWarning。此參數不會影響重新安裝步驟,這將始終引發錯誤。默認值為“不贊成使用”,但從0.22版開始,它將更改為np.nan。返回類型:
?train_sizes_abs:數組,形狀(n_unique_ticks,),dtype int。已用于生成學習曲線的訓練示例數。 請注意,ticks的數量可能少于n_ticks,因為重復的條目將被刪除。
?train_scores:數組,形狀(n_ticks,n_cv_folds)。訓練集得分。
?test_scores:數組,形狀(n_ticks,n_cv_folds)。測試集得分。
函數參考:sklearn中的學習曲線learning_curve函數
注釋2:
sklearn.model_selection.KFold
函數原型:KFold(n_split, shuffle, random_state)
關鍵參數解釋:
?n_split:要劃分的折數
?shuffle::每次都進行shuffle,測試集中折數的總和就是訓練集的個數
?random_state:隨機狀態
2.2、使用L1正則化的線性模型——套索回歸
?和嶺回歸一樣,套索回歸也會 將系數限制在非常接近0 的范圍內,但它限制的方式稱之為 L1 正則化。與L2 正則化不同的是,L1 正則化會導致在使用套索回歸的時候,有一部分特征的系數會正好等于0。也就是說,有一些特征會被模型忽略掉。下面再用糖尿病數據驗證套索回歸。
import numpy as np
from sklearn.linear_model import Ridge #導入套索回歸
from sklearn.linear_model import Lasso #導入嶺回歸
from sklearn.datasets import load_diabetes #載入糖尿病數據
from sklearn.model_selection import train_test_split #切分訓練集和測試集
import matplotlib.pyplot as plt
X, y = load_diabetes().data, load_diabetes().target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=8)
#取不同的 alpha 來看參數對套索回歸的影響
lasso01= Lasso(alpha=0.1, max_iter=100000).fit(X_train, y_train)#max_iter迭代次數
lasso1= Lasso(alpha=1, max_iter=100000).fit(X_train, y_train)
lasso00001= Lasso(alpha=0.0001, max_iter=100000).fit(X_train, y_train)
#取不同的 alpha 來看參數對嶺回歸的影響
ridge01 = Ridge(alpha=0.1).fit(X_train, y_train)
#繪制 alpha =1 時的模型系數
plt.plot(lasso1.coef_, 's', label = "Lasso alpha=1")
#繪制 alpha =0.1 時的模型系數
plt.plot(lasso01.coef_, '^', label = "Lasso alpha=0.1")
#繪制 alpha =0.00001 時的模型系數
plt.plot(lasso00001.coef_, 'v', label = "Lasso alpha=0.00001")
#繪制 alpha =0.1 時的模型系數
plt.plot(ridge01.coef_, 'o', label = "Ridge alpha=0.1")
plt.legend(loc=(0, 1.05), ncol=2)
plt.xlabel("Coefficient index")
plt.ylabel("Coefficient magnitude")
plt.show()
執行結果如下圖,在alpha=1的時候,不僅大部分系數為0,僅存的幾個非零系數也特別小。在alpha=0.1的時候,雖然大部分系數為0,但僅存的幾個非零系數比alpha=1的時候的大。在alpha=0.0001的時候,模型幾乎沒有被正則化。
2.3、L1正則化和L2正則化的對比
?在實際應用中,嶺回歸是兩個模型中的優選。但要依據實際情況而定。
?數據集中的特征過多,而其中只有一小部分是真正重要的,選L1正則化的模型,如套索回歸。
?數據集中的特征本來就不多,而且每一個都有重要的作用,選L2正則化的模型,如嶺回歸。
三、其他線性模型
彈性網模型(Elastic Net):綜合了套索回歸和嶺回歸的懲罰因子。實踐中,這兩個模型的組合效果是組好的,但需要調節2個參數,即L1正則化參數和L2正則化參數。
邏輯斯蒂回歸(Logis Regression)
線性支持向量機(Linear SVM)