利用線性Lasso模型類LineLassoModel類(見博文《最優化方法Python計算:有約束優化應用——線性Lasso回歸預測器》)及分類器類Classification(見博文《最優化方法Python計算:無約束優化應用——線性回歸分類器》),下列代碼實現線性Lasso分類器。
class LassoClassifier(Classification, LineLassoModel): #線性Lasso分類器def __init__(self, alpha = 1.0):self.alpha = alphaself.tagVal = np.round
第1~4行用LineLassoModel和Classification類實現線性Lasso分類器類LassoClassifier。第2~4行的構造函數初始化正則化系數alpha,將標簽值函數tagVal設置為四舍五入函數numpy.round,以適于分類預測。
綜合案例
文件heart_failure_clinical_records_dataset.csv(來自UC Irvine Machine Learning Repository)記錄了299例心力衰竭病人的數據。
age | anaemia | ? \cdots ? | diabetes | $cdots$ | ? \cdots ? | platelets | sex | ? \cdots ? | ? \cdots ? | smoking | time | DEATH_EVENT |
---|---|---|---|---|---|---|---|---|---|---|---|---|
75 | 0 | ? \cdots ? | 0 | ? \cdots ? | ? \cdots ? | 265000 | 1.9 | ? \cdots ? | ? \cdots ? | 0 | 4 | 1 |
? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? |
70 | 0 | ? \cdots ? | 0 | ? \cdots ? | ? \cdots ? | 244000 | 1.2 | ? \cdots ? | ? \cdots ? | 0 | 66 | 1 |
? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? |
60 | 1 | ? \cdots ? | 0 | ? \cdots ? | ? \cdots ? | 210000 | 1.7 | ? \cdots ? | ? \cdots ? | 0 | 82 | 1 |
? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? |
55 | 0 | ? \cdots ? | 0 | ? \cdots ? | ? \cdots ? | 263358.03 | ? \cdots ? | ? \cdots ? | 1 | 1 | 241 | 1 |
? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? | ? \cdots ? |
50 | 0 | ? \cdots ? | 0 | ? \cdots ? | ? \cdots ? | 395000 | 1.6 | ? \cdots ? | ? \cdots ? | 1 | 285 | 0 |
其中,
- age - 患者的年齡(年)
- anaemia - 患者是否貧血(布爾值)
- creatinine phosphokinase(CPK) - 血液中CPK酶的水平(mcg/L)
- diabetes - 患者是否患有糖尿病(布爾值)
- ejection fraction - 每次收縮時離開心臟的血液百分比(百分比)
- high blood pressure - 患者是否患有高血壓(布爾值)
- platelets - 血液中的血小板(kiloplatelets/mL)
- sex - 性別(二進制)
- serum creatinine - 血液中的血清肌酐水平(毫克/分升)
- serum sodium - 血液中的血清鈉水平(mEq/L)
- smoking - 患者是否吸煙(布爾值)
- time - 隨訪期(天數)
- DEATH_EVENT - 患者是否在隨訪期間死亡(布爾值)
將表示患者是否死亡的\texttt{DEATH_EVENT}作為標簽數據,其余12個數據項作為特征數據,則判斷患者是否會在就醫時死亡構成一個2-分類問題。下列代碼用這一數據集訓練測試一個線性分類LinearClassifier(見博文《最優化方法Python計算:無約束優化應用——線性回歸分類器》)模型。
import numpy as np #導入numpy
LassoClassifier,LinearClassifier
np.set_printoptions(precision=4)
data = np.loadtxt('heart_failure_clinical_records_dataset.csv', delimiter=',', dtype=object, skiprows=1) #讀取數據文件
X = np.array(data) #轉換為數組
Y = X[:, 12].astype(int) #讀取標簽數據
X = np.delete(X, [12], axis = 1).astype(float) #特征數據
m, n = X.shape
print('共有%d個數據樣本'%m)
a=np.arange(m) #樣本下標集
np.random.seed(1766) #隨機種子
print('隨機抽取%d個樣本作為訓練數據。'%(m // 2))
train = np.random.choice(a, m // 2, replace = False) #隨機取得一半作為訓練集下標
test = np.setdiff1d(a, train) #測試集下標
print('LINE REGRESSION:')
heart_failure = LinearClassifier() #構造線性回歸模型
heart_failure.fit(X[train], Y[train]) #訓練模型
coef, inte = heart_failure.coef_inte() #模型的系數和截距
print('系數:', coef)
print('截距:%.4f'%inte)
acc = heart_failure.score(X[test], Y[test]) * 100 #測試模型
print('對其余%d個樣本數據測試,準確率:%.4f'%(m - m // 2, acc) + '%')
程序的第3~8行讀取文件數據并將其分離成樣本特征數據X和標簽數據Y。第11~14行在數據集中隨機選取一般作為訓練數據,下標為train,另一半作為測試數據,下標為test。第16行用LinearClassifier類創建一個線性分類模型heart_failure。第17行調用heart_failure的fit函數用X[train]和Y[train]訓練heart_failure。第18行調用heart_failure的coef_inte函數計算系數和截距。第21行調用heart_failure的score函數用X[test]和Y[test]測試heart_failure。運行程序,輸出
共有299個數據樣本
隨機抽取149個樣本作為訓練數據。
LINE REGRESSION:
訓練中...,稍候
17次迭代后完成訓練。
系數: [ 6.1401e-03 -2.1315e-02 4.1355e-05 -1.0871e-02 -9.2742e-03 -2.2379e-02-1.8753e-07 7.4815e-02 -9.0710e-03 -1.5951e-01 3.4964e-02 -2.5166e-03]
截距:1.9301
對其余150個樣本數據測試,準確率:90.6667%
即經17次迭代,用X[train]和Y[train]訓練了線性分類模型。用X[test]和Y[test]測試該模型得到90.667%的正確率。接下來我們分別用X[train]、Y[train]和X[test]、Y[test]訓練和測試一個線性Lasso分類器LassoClassifier模型。前一程序之后添加下列代碼
……
print('LASSO REGRESSION:')
heart_failure = LassoClassifier(alpha = 0.5) #構造Lasso分類模型
heart_failure.fit(X[train], Y[train]) #訓練模型
coef, inte = heart_failure.coef_inte()
print('系數:',coef)
print('截距:%.4f'%inte)
acc = heart_failure.score(X[test], Y[test]) * 100 #測試模型
print('對其余%d個樣本數據測試,準確率:%.4f'%(m - m // 2, acc) + '%')
程序第1行的省略號表示前一程序的代碼。第3行將heart_failure聲明為LassoClassifier類對象,傳遞給構造函數的參數alpha為0.5。第4行用X[train]、Y[train]訓練heart_failure。第8行用X[test]、Y[test]測試heart_failure。運行程序,輸出
LASSO REGRESSION:
訓練中...,稍候
36次迭代后完成訓練。
系數: [ 3.3045e-01 -1.5398e-07 5.6651e-02 7.3073e-08 -4.6018e-01 -7.5823e-06-1.1760e-08 4.6328e-01 -9.9697e-02 -1.0726e-01 1.0053e-02 -6.2893e-017.8053e-01]
截距:0.7805
對其余150個樣本數據測試,準確率:90.6667%
經36次迭代,用X[train]、Y[train]訓練的Lasso分類模型,對X[test]、Y[test]測試的正確率為90.667%{}。觀察Lasso分類模型的系數,有一些元素的絕對值小于 1 0 ? 4 10^{-4} 10?4。這意味著這些系數對應的特征數據對標簽值的貢獻微弱。刪掉這些數據項對預測正確率的影響不大,且可提高訓練線性模型的效率。下列代碼作這樣的嘗試,追加在前兩個程序尾部。
……
a = np.where(np.abs(coef) < 1e - 4)[0] #LASSO回歸絕對值小于1/10000的系數下標
print('LASSO回歸絕對值小于1/10000的系數下標:%s'%a)
X = np.delete(X, a, axis=1) #刪掉這些系數對應的特征數據
print('LINE REGRESSION:')
heart_failure = LinearClassifier() #構造線性回歸模型
heart_failure.fit(X[train], Y[train]) #訓練模型
coef, inte=heart_failure.coef_inte()
print('系數:', coef)
print('截距:%.4f'%inte)
acc = heart_failure.score(X[test], Y[test]) * 100 #測試模型
print('對其余%d個樣本數據測試,準確率:%.4f'%(m - m // 2, acc) + '%')
程序第1行的省略號表示程序8.6、8.7的代碼。第2行調用numpy的where函數計算LassoClassifier對象表示的Lasso分類模型的系數coef中絕對值小于 1 0 ? 4 10^{-4} 10?4的下標集a。第4行在X中刪除由a指示的數據列。第6行將heart_{}failure聲明為線性分類模型。第7行用X[train]、Y[train]訓練線性分類模型。第11行對X[test]、Y[test]測試該模型。運行程序,輸出
……
LASSO回歸絕對值小于1/10000的系數下標:[1 3 5 6]
LINE REGRESSION:
訓練中...,稍候
16次迭代后完成訓練。
系數: [ 6.1677e-03 4.5319e-05 -9.4294e-03 7.5720e-02 -9.3499e-03 -1.5180e-014.0119e-02 -2.4872e-03]
截距:1.8346
對其余150個樣本數據測試,準確率:90.6667%
即特征數據降維后,線性分類模型經16次迭代得到訓練,測試知正確率與降維前保持一致。
寫博不易,敬請支持:
如果閱讀本文于您有所獲,敬請點贊、評論、收藏,謝謝大家的支持!